Factory Method Pattern in Java and Python
This article exists on YouTube
The entire content of this article is also available on YouTube. It's your choice: if you prefer video content, you can watch it on YouTube. If you prefer reading, feel free to continue here.
What is a Factory Method Pattern?
The Factory Method Pattern is a programming pattern used in software engineering and it is part of the group of creational patterns. It may be used in any object-oriented programming language, such as Java, Python, C++, and so on. What it helps to do is creating objects within superclasses while allowing subclasses to decide upon the type of object to create. In other words, it differentiates between a creator and a product.
The general idea is that a creator asks for a product or rather a product type. What the creator then does is delegate to another class that does the necessary steps to create the object depending on its context. It is as if we would ask to find a bird. What type of bird depends on the context. A hunter might look for ducks or geese, while a nature scientist might rather look for some endangered or migratory birds which could be the California Condor or Hummingbirds.
The class that creates the product only operates within the visibility of an abstract definition of a product. This way loose coupling between the creator and the product is created. What this means is that it only knows the methods that are defined within the abstract definition. What the actual objects' class has defined outside of the abstract class it implements, is of no importance to the creating class, because it does not need to control any other parts of the object other than those of the abstract definition.
So what is the Factory Method Pattern used for? This is particularly useful in scenarios where objects are created without specifying the exact class that will be instantiated. Examples of real-world use include GUI frameworks, database drivers, logging libraries, dependency injection containers, and testing frameworks.
Within the area of GUI development several use cases may facilitate the use of the Factory Method Pattern, i.e. creating the different UI elements necessary on the masks. The GUI framework Java Swing also makes use of this pattern within the JButton class with the method createUI.
Applications that make use of databases may use libraries or frameworks who create instances of database connection objects. The JDBC (Java Database Connectivity) framework has the DriverManager class that uses the Factory Method Pattern within the static method getConnection to create Connection objects to interact with a particular database. Clients do not need to create any instance of the DriverManager in order to get the Connection object. The getConnection method itself delegates the creation of Connection objects to registered JDBC drivers.
Similar to the database drivers there are also logging libraries such as Log4j and SLF4J that make use of the Factory Method Pattern to create instances of logger objects. Logging could be implemented i.e. for file-based logging or console-based logging.
Within the area of dependency injection one could name the Java Spring Framework where beans can be requested from the container who is the one that uses the Factory Method Pattern to create and configure instances of objects based on its configuration.
What is the structure of a Factory Method Pattern?
- AbstractCreator
The AbstractCreator is an abstract class or interface that declares the so-called factory method. This method serves as the interface for creating objects, but it does not provide the implementation. The AbstractCreator may also contain methods that are common to all ConcreteCreator classes. - ConcreteCreator1 and ConcreteCreator2
The ConcreteCreator1 and ConcreteCreator2 classes are subclasses of the AbstractCreator class. The subclasses provide their own implementation to everything that has been defined within their superclasses. They are also responsible for instantiating objects ConcreteProductA1 and ConcreteProductA2. - AbstractProduct
The AbstractProduct class is an interface or abstract class that defines what a product should look like. It declares operations that the classes ConcreteProductA1 and ConcreteProductA2 must implement. - ConcreteProductA1 and ConcreteProductA2
The ConcreteProductA1 and ConcreteProductA2 classes are concrete classes implementing everything that is declared within the AbstractProduct class. They encapsulate the implementation details of individual so-called products.
Example Codes
There are a number of programming languages where the Abstract Factory Pattern can prove useful. Every language that supports the construct of classes can make use of this pattern.
All the codes within this article can also be found on the GitHub repository programming-patterns and in there within the directory Factory Method Pattern.
Java Example
The following example is a Java application putting the Factory Method Pattern into action. All the following files need to be placed into the same folder so that the code within the files can work properly, because the files also reference each other. Being the smallest possible code example, this little project consists of seven Java files:
- AbstractProduct.java
- ConcreteProductA1.java
- ConcreteProductA2.java
- AbstractCreator.java
- ConcreteCreator1.java
- ConcreteCreator2.java
- Main.java
The first thing that needs to be defined is the abstract product. We define them as either abstract class or as an interface, because this can be seen as a general description of what parameters the product should have and what it can do.
public interface AbstractProduct {
void doSomething();
}
Out of this abstraction we will create two concretizations A1 and A2. These are the concrete products we will have the application create later.
public class ConcreteProductA1 implements AbstractProduct {
@Override
public void doSomething() {
System.out.println("Concrete Product A1 does something.");
}
}
public class ConcreteProductA2 implements AbstractProduct {
@Override
public void doSomething() {
System.out.println("Concrete Product A2 does something.");
}
}
The next step consists of defining the abstract creater class. Again, this can either be an abstract class or an interface. We also declare that a method named createProduct() needs to be implemented by the classes that implement this interface.
public interface AbstractCreator {
AbstractProduct createProduct();
}
Out of this class or interface we create two concrete creater classes 1 and 2 that implement the method createProduct().
public class ConcreteCreator1 implements AbstractCreator {
@Override
public AbstractProduct createProduct() {
return new ConcreteProductA1();
}
}
public class ConcreteCreator2 implements AbstractCreator {
@Override
public AbstractProduct createProduct() {
return new ConcreteProductA2();
}
}
And this is it already. The main construct of the Factory Method Pattern consists of these six Java files. The only thing that remains is to apply their logic within the executing main class. The main(...) method creates one instance each for the ConcreteCreator1 and ConcreteCreator2 class. After that both creators create a product using the method createProduct() one after the other. And after that both products execute the doSomething() method, showing that the two different concrete product classes are referenced and executed.
public class Main {
public static void main(String[] args) {
System.out.println("Factory Method Pattern in Java");
System.out.println("------------------------------");
System.out.println();
AbstractCreator creator1 = new ConcreteCreator1();
AbstractCreator creator2 = new ConcreteCreator2();
AbstractProduct productA1 = creator1.createProduct();
AbstractProduct productA2 = creator2.createProduct();
productA1.doSomething();
productA2.doSomething();
}
}
There also needs to be a Manifest.txt file within the same folder. This is a metadata file used primarily in JAR files. It contains information about the JAR file itself and its contents. It is placed within thie META-INF folder within the JAR archive file structure.
Main-Class: Main
To compile this code into an executable Java application which would be a JAR file, a couple of commands need to be executed from within the same directory. The commands are found within the build file.
@echo off
javac *.java
jar cvfm FactoryMethodDemo.jar Manifest.txt *.class
#!/bin/bash
javac *.java
jar cvfm FactoryMethodDemo.jar Manifest.txt *.class
Now that the compilation has taken place, there are new files within the same directory. Every JAVA file has its equivalent CLASS file, and there is also a file called FactoryMethodDemo.jar. This is the Java application that needs to be executed. The command for that is within the run file.
@echo off
java -jar FactoryMethodDemo.jar
#!/bin/bash
java -jar FactoryMethodDemo.jar
Testing the Java Example
Now that all the files are ready and within their correct location they can be put to test. First we need to compile the Java code and then we can execute it to see what it will print in the Windows Command Prompt or in the MacOS / Linux Terminal.
Python Example
The following example is a Python application putting the Factory Method Pattern into action. All the following files need to be placed into the same folder so that the code within the files can work properly, because the files also reference each other. Being the smallest possible code example, this little project consists of seven Python files:
- abstract_product.py
- concrete_product_a1.py
- concrete_product_a2.py
- abstract_creator.py
- concrete_creator_1.py
- concrete_creator_2.py
- main.py
The first thing that needs to be defined is the abstract product. We define it as an abstract class, because this can be seen as a general description of what parameters the product should have and what it can do. As this is an abstract class, we will make use of the abc module for its ABC (Abstract Base Class) and its @abstractmethod decorator.
from abc import ABC, abstractmethod
class AbstractProduct(ABC):
@abstractmethod
def doSomething(self):
self
Out of this abstraction we will create two concretizations A1 and A2. These are the concrete products we will have the application create later.
from abstract_product import AbstractProduct
class ConcreteProductA1(AbstractProduct):
def doSomething(self):
print("Concrete Product A1 does something.")
from abstract_product import AbstractProduct
class ConcreteProductA2(AbstractProduct):
def doSomething(self):
print("Concrete Product A2 does something.")
The next step consists of defining the abstract creater class. We also declare that a method named createProduct() needs to be implemented by the classes that implement this interface.
from abc import ABC, abstractmethod
class AbstractCreator(ABC):
@abstractmethod
def createProduct(self):
pass
Out of this class we create two concrete creater classes 1 and 2 that implement the method createProduct().
from abstract_creator import AbstractCreator
from concrete_product_a1 import ConcreteProductA1
class ConcreteCreator1(AbstractCreator):
def createProduct(self):
return ConcreteProductA1()
from abstract_creator import AbstractCreator
from concrete_product_a2 import ConcreteProductA2
class ConcreteCreator2(AbstractCreator):
def createProduct(self):
return ConcreteProductA2()
And this is it already. The main construct of the Factory Method Pattern consists of these six Python files. The only thing that remains is to apply their logic within the executing main class. The main(...) method creates one instance each for the ConcreteCreator1 and ConcreteCreator2 class. After that both creators create a product using the method createProduct() one after the other. And after that both products execute the doSomething() method, showing that the two different concrete product classes are referenced and executed.
from concrete_creator_1 import ConcreteCreator1
from concrete_creator_2 import ConcreteCreator2
def main():
print("Factory Method Pattern in Python")
print("--------------------------------")
print()
creator1 = ConcreteCreator1()
creator2 = ConcreteCreator2()
productA1 = creator1.createProduct()
productA2 = creator2.createProduct()
productA1.doSomething()
productA2.doSomething()
if __name__ == "__main__":
main()
There is no need to compile anything in Python. The code is executed directly using the python command under Windows and the python3 command under MacOS / Linux.
Testing the Python Example
Now that all the files are ready and within their correct location they can be put to test. Python does not need to be compiled before being run. Therefore we can execute it right away to see what it will print in the Windows Command Prompt or in the MacOS / Linux Terminal.
More Information
So, where do I have my information from? In general, there are lots of places on the internet that offer great information. But that is just one source of information. Another source would be books. Those have the advantage that usually several people work on the same book before it is released, raising the chance for distribution of good and proven information.
Head First - Design Patterns
Building Extensible and Maintainable Object-Oriented Software
A book that has proven to be a valuable asset within my personal library is Head First - Design Patterns by the publisher O'Reilly. It has a fun approach to this topic, having recurring characters, such as the Guru, the Developer, the Skeptical Developer, Joe, and many more.
Java Design Patterns
A Hands-On Experience with Real-World Examples
Another highly valuable book is Java Design Patterns: A Hands-On Experience with Real-World Examples by the publisher Apress. It offers a conservative and rather scientific approach to the subject. It also offers code examples in Java, although any object-oriented programming language applies to the design patterns shown here.