Welcome back! So far, you’ve learned about the Singleton Pattern and have seen how it ensures a class has only one instance with a global access point. Now, we’re moving on to another essential creational design pattern: the Factory Method Pattern. This pattern is all about creating objects in a much more flexible way than direct instantiation. You’ll learn how to implement your own factory methods to instantiate different types of objects and see how this pattern allows your code to handle new object types with ease.
The Factory Method Pattern is a creational design pattern that provides an interface for creating an object but allows subclasses to alter the type of objects that will be created. This pattern promotes loose coupling by eliminating the need to specify the exact class of the object that will be created. Instead, the instantiation is handled by subclasses.
You should consider using the Factory Method Pattern when object creation requires conditional logic, when working with large class hierarchies, or when developing frameworks and libraries that need to allow users to extend and customize object creation.
To understand how the Factory Method Pattern is implemented, let's break the process down into intermediate steps.
First, define an abstract base class Document
with an abstract method open
. This class will serve as the template for different types of documents.
Python1from abc import ABC, abstractmethod 2 3class Document(ABC): 4 @abstractmethod 5 def open(self): 6 pass
Next, create concrete subclasses of Document
. Each subclass will implement the open
method. For example, let's define WordDocument
and ExcelDocument
.
Python1class WordDocument(Document): 2 def open(self): 3 print("Opening Word document.") 4 5class ExcelDocument(Document): 6 def open(self): 7 print("Opening Excel document.")
Now, define an abstract base class DocumentCreator
with an abstract method create_document
. This class will provide the interface for creating documents.
Python1class DocumentCreator(ABC): 2 @abstractmethod 3 def create_document(self): 4 pass
Create concrete subclasses of DocumentCreator
. Each subclass will implement the create_document
method to instantiate and return a specific type of document.
Python1class WordDocumentCreator(DocumentCreator): 2 def create_document(self): 3 return WordDocument() 4 5class ExcelDocumentCreator(DocumentCreator): 6 def create_document(self): 7 return ExcelDocument()
Finally, use the factory methods to create document objects without specifying their concrete classes.
Python1if __name__ == "__main__": 2 creator = WordDocumentCreator() 3 doc = creator.create_document() 4 doc.open() 5 6 creator = ExcelDocumentCreator() 7 doc = creator.create_document() 8 doc.open()
In this example, we define the Document
class with an abstract method open
, and two concrete subclasses WordDocument
and ExcelDocument
that implement the open
method. We also create the DocumentCreator
abstract class with an abstract method create_document
, and two concrete subclasses WordDocumentCreator
and ExcelDocumentCreator
that implement the create_document
method to return instances of WordDocument
and ExcelDocument
, respectively. This step-by-step breakdown showcases a simple implementation of the Factory Method Pattern using different document types in Python.
Here's the complete implementation of the Factory Method Pattern based on the steps we've discussed:
Python1from abc import ABC, abstractmethod 2 3class Document(ABC): 4 @abstractmethod 5 def open(self): 6 pass 7 8class WordDocument(Document): 9 def open(self): 10 print("Opening Word document.") 11 12class ExcelDocument(Document): 13 def open(self): 14 print("Opening Excel document.") 15 16class DocumentCreator(ABC): 17 @abstractmethod 18 def create_document(self): 19 pass 20 21class WordDocumentCreator(DocumentCreator): 22 def create_document(self): 23 return WordDocument() 24 25class ExcelDocumentCreator(DocumentCreator): 26 def create_document(self): 27 return ExcelDocument() 28 29if __name__ == "__main__": 30 creator = WordDocumentCreator() 31 doc = creator.create_document() 32 doc.open() 33 # Output: Opening Word document. 34 35 creator = ExcelDocumentCreator() 36 doc = creator.create_document() 37 doc.open() 38 # Output: Opening Excel document.
One of the key advantages of the Factory Method Pattern is its flexibility and extensibility. For instance, adding a new type of document, such as a PdfDocument
, does not require changes to the existing DocumentCreator
or Document
classes. Instead, you can create a new subclass of Document
and a corresponding subclass of DocumentCreator
.
Python1class PdfDocument(Document): 2 def open(self): 3 print("Opening PDF document.") 4 5class PdfDocumentCreator(DocumentCreator): 6 def create_document(self): 7 return PdfDocument()
This extensibility makes the pattern ideal for applications where new types of objects are frequently added. You can introduce new products without altering the existing structure, enhancing the maintainability and evolvability of your codebase.
The Factory Method Pattern is essential because it promotes flexibility and scalability in your code designs. By delegating the creation of objects to factory methods, you can easily introduce new types of objects without changing the existing code, leading to better maintainability. Whether you're developing software libraries, frameworks, or complex applications, this pattern helps you manage and scale object creation efficiently. Ready to enhance your coding skills? Let's delve into the Factory Method Pattern and see how you can apply it to write cleaner, more maintainable code. Let's start!