This chapter covers the simple factory pattern.
Intent
Create an object without exposing the instantiation logic to the client.
Concept
In object-oriented programming, a factory is a special kind of object that can create other objects. A factory can be invoked in many ways, but most often, it uses a method that can return objects with varying prototypes. Any subroutine that can help create these new objects is considered a factory. The ultimate purpose of using a factory method is to abstract the object creational mechanism (or process) from the consumers of the application.
Real-World Example
Consider a car manufacturing company that manufactures different models of a car. They must have a factory with different production units. Some of these units can produce the parts that are common to all models, while other units are dedicated to produce the model-specific parts. When they make the final product, they assemble the model-specific parts with the common parts. From a client’s point of view, a car is built from a car factory; the client does not know how the car is built. But if you investigate further, you see that based on the model of the car, a production unit of the factory varies the parts. For example, a particular car model can support a manual gearbox only and another model can support both the automatic and manual gearbox. So, based on the model of the car, the car factory constructs the particular gearbox for the car.
Consider a simpler example. When a kid demands a toy from his/her parent, the child does not know how the parent will fulfill the demand. The parent, in this case, is considered a factory for their small child. Now think from the parent’s point of view. The parent can make the toy himself/herself or purchase a toy from a shop to make their kid happy.
Computer-World example
A simple factory is not treated as a standard design pattern in the GoF’s famous book, but the approach is common to any application that you write where you want to separate the code that varies a lot from the part of code that does not vary. It is assumed that you try to follow this approach in any application you write.
A simple factory is considered the simplest form of factory method patterns (or abstract factory patterns). So, you can assume that any application that follows either the factory method pattern or the abstract factory pattern, also supports the concept of simple factory pattern’s design goals.
Note
The static getInstance()method of the java.text.NumberFormat class is an example of this category.
Let’s follow the implementation in which I discuss this pattern in a common use case.
Illustration
In this example, there are two types of animals: dogs and tigers. The object creational process depends on users’ input.
I assume that each of them can speak and they prefer to perform some actions.
SimpleFactory is the factory class and simpleFactory (note that the “s” is not in caps) is an object of the class. In the client code (SimpleFactoryPatternExample class), you see the following line.
I have separated the code that varies from the code that are least likely to vary. This approach helps you remove tight coupling in the system. (How? Follow the “Q&A Session” section.)
Note
In some applications, you may notice a slight variation of this pattern where use of parameterized constructors is suggested. So, in those applications, to get a preferredType object, you may need to use a line of code similar to this line: preferredType=simpleFactory.createAnimal(“Tiger”).
Class Diagram
Package Explorer View
Implementation
Output
Here’s the output.
Case1. User input:0
Case2. User input:1
Case3. An unwanted user input:2
Q&A Session
- 1.
In this example, the clients are delegating the objects’ creation through the SimpleFactory. But instead, they could directly create the objects with the “new” operator. Is this correct?
No. These are the key reasons behind the preceding design.An important object-oriented design principle is to separate the part of your code that is most likely to change from the rest.
In this case, only “the objects creational part” varies. I assume that these animals must speak and perform actions, and I do not need to vary that portion of code inside the client. So, in the future, if you need to modify the creational process, you need to change only the createAnimal() method of SimpleFactory class. This client code is unaffected due to those modifications.
“How are you creating objects?” is hidden in the client code. This kind of abstraction promotes security.
This approach can help you avoid lots of if/else blocks (or switch statements) inside the client code because they make your code look clumsy.
- 2.What are the challenges associated with this pattern?
Deciding which object to instantiate becomes complex over time. In those cases, you should prefer the factory method pattern.
If you want to add a new animal or delete an existing one, you need to modify the createAnimal() method of the factory class. This approach clearly violates the open-closed principle (which basically says that your code should be open for extension but closed for modification) of SOLID principles.
Note
SOLID principles were promoted by Robert C. Martin. You can learn about them at https://en.wikipedia.org/wiki/SOLID .
- 3.I learned that programming with an abstract class or interface is always a better practice. So, to make a better implementation, you could write something like this:abstract class ISimpleFactory{public abstract IAnimal createAnimal() throws IOException;}class SimpleFactory extends ISimpleFactory{//rest of the code}
Is this correct?
Yes. Programming with the abstract class or an interface is always a better practice. This approach can prevent you from future changes because any newly added classes can simply implement the interface and settle down in the architecture through polymorphism. But if you solely depend on concrete classes, you need to change your code when you want to integrate a new class in the architecture, and in such a case, you violate the rule that says that your code should be closed for modifications.
So, your understanding is correct. You could use such a construct to make it a better program. But ultimately, you learn the factory method pattern (see Chapter 4), where you need to defer the instantiation process to subclasses. So, you are advised to write programs with an abstract class or an interface in such a case.
- 4.
Can you make the factory class (SimpleFactory) static?
No. In Java, you are not allowed to tag the word static with a top-level class. In other words, by design, the compiler always complains about the top-level static classes in Java.