Over a million developers have joined DZone.
{{announcement.body}}
{{announcement.title}}

Factory Method vs. Simple Factory

DZone's Guide to

Factory Method vs. Simple Factory

They're easy to mix up, but it's critical to get Factory methods and Simple Factories right. Know when to apply each to make sure you're crushing your business reqs.

· Java Zone
Free Resource

The single app analytics solutions to take your web and mobile apps to the next level.  Try today!  Brought to you in partnership with CA Technologies

When interviewing a senior developer, my favorite question is, "Do you know design patterns?"

Obviously, the answer is always yes, so then I ask them about the design patterns they are familiar with and use in their projects?

In most cases, I get "Factory" and "Singleton."

As this is an article on the Factory Pattern, we'll ignore the Singleton interview discussion here.

The next question from my side is, "Tell me a business case and write down code fragments for the Factory method."

But unfortunately, I often get back the example of Shape — a well-known example found on Google — and they end up writing a Simple Factory, which is not considered a Design pattern.

In this article, I will not show how to write the Simple Factory and Factory methods. Rather, I prefer to discuss what are they and when to use them.

After taking enough interviews, I realized some points:

  1. We are actually trying to memorize design patterns, not understand the problem it tries to solve.

  2. Another realization is that we fail to analyze the business justification and apply patterns based on them. Rather, we try to find where we can fit the pattern that I know into the business case.

Simple Factory

 /**
*
*/
package com.example.factory;

/**
* @author Shamik Mitra
*
*/
public interface ITV {

    public void createTV();

}

-------------------------------
SimpleFactory.java
------------------------

/**
*
*/
package com.example.factory;

/**
* @author Shamik Mitra
*
*/
public class TVSimpleFactory {

    enum TVMODE{COLOR,LED,LCD,THREEDIM};

    public static ITV getTV(TVMODE mode){

        if(mode.equals(TVMODE.LED)){
            return new ITV(){

                @Override
                public void createTV() {
                    System.out.println("LED TV");

                }

            };
        }
        return null;
    }

    public static void main(String[] args) {
        TVSimpleFactory.getTV(TVMODE.LED).createTV();
    }

}


Justification

With the Simple Factory, we try to abstract the creation details of the product from our caller. The only thing our caller knows, by calling a Static method and passing the desired parameter it, is that it returns an object of the TV type. But how TV is created, the client code does not know. Actually, they do not care how you create that product. I only care about viewing Sony LED TVs, not how Sony manufactures them.

So whenever you see there are chances to create many implementations of a product go for the Simple factory. But please don’t take this as a Silver bullet. Try to understand the business justification then apply the pattern on it may be it is provocative to use Simple factory for a Business requirements but it may happen you view the problem in a small scope but at a broader scope your decision hurt the design, read the next to see how a simple change in business requirements can hurt the design.

Factory Method

Use the Factory method if the business requirements are more than just product creation. To be precise, if you want to control product creation steps and want to control every step, and steps are customized, then we use the Factory method. To put it a simple way, if you want to control an algorithm/strategy of a family of products, you can think about the Factory method pattern. It plays very well with the GOF Template pattern, where a Template method controls the strategy/algorithm and its steps to create the child are abstracted.

Use the Factory method when you want to make a Framework where you want to take a control from the creation of the Object to the management of that Object. That's unlike the Simple factory, where you only care about the creation of a product, not how to create and manage it.

Recall the Headfirst Pizza example, where the orderPizza() method, creates Pizza, then bakes, cuts, and boxes it. So it is nothing but an algorithm that remains constant across all Pizzas and notes that orderPizza is a template Method.

But you can also add an abstract method called applyTax() in orderPizza(), in the actual implementations (children) of the factory, you actually apply tax computation on a Region basis, so I can tell I have fine control over the Pizza lifecycle — not only the creation, but also the management part.

Back to our example. Now, say our business requirements want us to not only to create the TV, but also take orders and ship the TV based on whether a city shipping charge is applicable.

So, we need to create an algorithm that will create different TVs and ship them. It calculates a shipping charge. The Factory method pattern is ideal here, but we can't achieve it via Simple Factory, so a change is needed in our design

Coding

We create an Interface for TV called ITV. LED TV and black&White TV implement this interface. After that, we create an abstract class called AbstractFactory where we maintain the algorithm/strategy in a template method and abstract the necessary part of the strategy. So, in the subclass of the factory, we can implement them according to business requirement.

Coding Template

Interface of Product

 /**
*
*/
package com.example.factory;

/**
* @author Shamik Mitra
*
*/
public interface ITV {

    public void createTV();

}

-------------------------
AbstractFactory Class
------------------------
/**
*
*/
package com.example.factory;

import com.example.factory.TVSimpleFactory.TVMODE;

/**
* @author Shamik Mitra
*
*/
public abstract class AbstractFactory {

    public final void orderTV() {
        createTV();
        int charge= shippingCharge();
        System.out.println("Shipping charge :: " + charge + " INR");

    }

    protected abstract int shippingCharge();

    protected abstract void createTV();

}


-----------------------
Concrete Factory
----------------------
/**
*
*/
package com.example.factory;


/**
* @author Shamik Mitra
*
*/
public class LEDTVFactory extends AbstractFactory {
    @Override
    public int shippingCharge() {
        // TODO Auto-generated method stub
        return 1000;
    }

    @Override
    public void createTV() {

        new ITV() {
            @Override
            public void createTV() {
                System.out.println("LED TV");

            }

        }.createTV();

    }

    public static void main(String[] args) {
        AbstractFactory factory = new LEDTVFactory();
        factory.orderTV();
    }
}

Justification 

With the Factory method, we not only abstract product creation, but take one step further. Here, we also abstract the factory that produces the TV. So the benefits are that we can control the creation and management of the product (i.e TV). If you examine the above code, you can see we abstract the TV with the ITV interface, and in the Abstract factory, we create a template method that controls the TV lifecycle — create TV and shipping cost calculations — and make them abstract so children of the abstract factory can change them accordingly. 

We can say the Factory method abstracts the creator from the caller. It is one level more abstract than Simple factory.

Benefits

  • Create a framework.

  • Control product lifecycle.

CA App Experience Analytics, a whole new level of visibility. Learn more. Brought to you in partnership with CA Technologies.

Topics:
design pattens ,factory method pattern ,factory pattern ,java ,tutorial

Opinions expressed by DZone contributors are their own.

THE DZONE NEWSLETTER

Dev Resources & Solutions Straight to Your Inbox

Thanks for subscribing!

Awesome! Check your inbox to verify your email so you can start receiving the latest in tech news and resources.

X

{{ parent.title || parent.header.title}}

{{ parent.tldr }}

{{ parent.urlSource.name }}