Factory design patterns
I find this factory word quite confusing when talking about design patterns. there is static factory, then factory or Simple factory, then factory method and abstract factory. Let’s understand each of them one by one.
Static factory method:
This was a design technique not present in Gang of four book. It say that consider static factory methods over constructor to create an Object.
Why Static Factory Methods?
- One advantage of static factory methods is that, unlike constructors, they have names. Constructors have fixed name and only differentiated by function signature which also has limitations. If the parameters to a constructor do not, in and of themselves, describe the object being returned, a static factory with a well-chosen name is easier to use and the resulting client code easier to read.
- A second advantage of static factory methods is that, unlike constructors, they are not required to create a new object each time they’re invoked (Like singleton pattern, flyweight pattern)
- A third advantage of static factory methods is that, unlike constructors, they can return an object of any subtype of their return type.
Disadvantages of static factory method
- The main limitation of providing only static factory methods is that classes without public or protected constructors cannot be subclassed
- A second shortcoming of static factory methods is that they are hard for programmers to find.
- This shortcoming is fixable by using standard names for static factory methods.
Here is the common naming convention for static factory method
common names for static factory methods. This list is far from exhaustive:
- from — A type-conversion method that takes a single parameter and returns a corresponding instance of this type, for example: Date d = Date.from(instant);
- of — An aggregation method that takes multiple parameters and returns an instance of this type that incorporates them, for example: Set faceCards = EnumSet.of(JACK, QUEEN, KING);
- valueOf — A more verbose alternative to from and of, for example: BigInteger prime = BigInteger.valueOf(Integer.MAX_VALUE);
- instance or getInstance — Returns an instance that is described by its parameters (if any) but cannot be said to have the same value, for example: StackWalker luke = StackWalker.getInstance(options);
- create or newInstance — Like instance or getInstance, except that the method guarantees that each call returns a new instance, for example: Object newArray = Array.newInstance(classObject, arrayLen);
- getType — Like getInstance, but used if the factory method is in a different class. Type is the type of object returned by the factory method, for example: FileStore fs = Files.getFileStore(path);
- newType — Like newInstance, but used if the factory method is in a different class. Type is the type of object returned by the factory method, for example: BufferedReader br = Files.newBufferedReader(path);
- type — A concise alternative to getType and newType, for example: List litany = Collections.list(legacyLitany); In summary, static factory methods and public constructors both have their uses, and it pays to understand their relative merits. Often static factories are preferable, so avoid the reflex
Now let’s discuss about factory design pattern.
Factory Pattern (Simple Factory): Focuses on creating objects of a single type or a limited set of related types. Factory is “fixed”, in that you have just one implementation with no subclassing.
Factory Method (GOF): Define an interface for creating an object, but let subclasses decide which class to instantiate. Factory Method lets a class defer instantiation to subclasses.
Abstract Factory (GOF): Provide an interface for creating families of related or dependent objects without specifying their concrete classes.
When to use which?
Factory: Client just need a class and don’t bother about implementer
Factory Method: Client doesn’t know what concrete classes it will be required to create the object
AbstactFactory: When your system has to create multiple families of products without exposing the implementation details.
Abstract Factory classes are often implemented with Factory Method.
If we have many static factory methods in our class to create Object then you can move all of these static methods to a separate factory class. This way static factory method and Simple factory are related
Let’s understand each of the 3 patterns with an example. This example uses Animal Interface Dog and Tiger are concrete classes.
Simple Factory
Factory method
Abstract factory
Increasing level of abstraction in these design patterns: Simple Factory, Factory Method, and Abstract Factory. Here’s a breakdown
Simple Factory (Least Abstraction):
- Function: Creates concrete objects directly. It acts as a central location for object creation, often using conditional statements to choose the appropriate class based on input parameters.
- Example: Imagine a function
createShape(String shapeType)
that returns aCircle
object ifshapeType
is "circle" and aRectangle
object if it's "rectangle."
Factory Method (One Layer of Abstraction):
- Function: Defines an interface (or abstract class) for creating objects. Subclasses of the factory implement the creation logic for specific concrete classes. This provides more flexibility as the specific object creation logic is delegated to subclasses based on the type needed.
- Example: Create an interface
ShapeFactory
with a methodcreateShape()
. Then, have subclasses likeCircleFactory
andRectangleFactory
that implementcreateShape()
to return the appropriate concrete object (Circle
orRectangle
).
Abstract Factory (Two Layers of Abstraction):
- Function: Provides an interface for creating families of related objects. This is the most abstract factory, offering a factory of factories. Each concrete factory creates a set of objects that work together.
- Example: Consider a scenario where you have different UI component styles (e.g., Light and Dark). You could define an abstract factory
GUIComponentFactory
with methods likecreateButton()
andcreateLabel()
. Then, have concrete factories likeLightThemeComponentFactory
andDarkThemeComponentFactory
that implement these methods to return the appropriate UI components (e.g.,LightButton
andDarkButton
) specific to their theme.
Here’s an analogy to further illustrate the increasing abstraction:
- Simple Factory: Like a vending machine with buttons for specific products (concrete objects).
- Factory Method: Like a restaurant with different chefs (subclasses) specializing in specific dishes (concrete objects).
- Abstract Factory: Like a department store with different departments (concrete factories) selling related products (families of objects) within a particular category (theme).
In essence, as you move from Simple Factory to Factory Method and Abstract Factory, you gain more flexibility and decoupling between object creation logic and client code, but at the cost of increasing complexity. The choice of which pattern to use depends on the specific needs of your project and the level of control and flexibility required for object creation.