Lesson 2
Factory Method Pattern
Understanding the Factory Method

Welcome back! We have already covered the Singleton pattern and how it ensures a class has only one instance. Now, let's dive into another essential creational design pattern: the Factory Method pattern. This lesson will guide you through understanding the Factory Method pattern, a powerful tool used to define an interface for creating an object but allows subclasses to alter the type of objects that will be created.

What You'll Learn

In this lesson, you'll gain a solid understanding of the Factory Method pattern in Java. We will focus on:

  • What the Factory Method pattern is and why it is used.
  • How to implement the Factory Method pattern using a factory class.
  • Creating different types of document classes (WordDocument and ExcelDocument) and generating their instances via the factory method.
The Factory Pattern

The Factory Method pattern is a creational design pattern that provides an interface for creating objects in a superclass but allows subclasses to alter the type of objects that will be created. Instead of calling a constructor directly to create an object, the client calls a factory method defined by an abstract class or interface, which delegates the process to derived classes. This approach promotes loose coupling and adheres to the Open/Closed Principle, allowing a system to be extended without modifying existing code.

We'll walk through a code example involving Document, WordDocument, and ExcelDocument classes, managed by a DocumentFactory class.

Step 1: Define the Document Class

First, we define an abstract class for our documents.

Java
1public abstract class Document { 2 // Abstract method to be implemented by concrete document types 3 public abstract void open(); 4}

The Document abstract class declares an abstract method open that all document types must implement. This provides a common contract for all documents.

Step 2: Implement Concrete Document Classes

We create two concrete implementations of the Document class, WordDocument and ExcelDocument.

Java
1public class WordDocument extends Document { 2 @Override 3 public void open() { 4 System.out.println("Opening Word Document."); 5 } 6} 7 8public class ExcelDocument extends Document { 9 @Override 10 public void open() { 11 System.out.println("Opening Excel Document."); 12 } 13}

WordDocument and ExcelDocument classes extend the Document class, thereby providing specific behavior for opening Word and Excel documents respectively.

Step 3: Create the Factory Class

Next, we create a factory class that provides a method to create instances of Document.

The factory class encapsulates the logic for creating various types of documents without exposing the creation logic to the client. This ensures that the client code doesn't need to know the details of how the documents are created. Instead, it simply calls the factory method and receives the appropriate document instance.

Java
1public class DocumentFactory { 2 // Enum to define supported document types 3 public enum DocumentType { 4 WORD, EXCEL 5 } 6 7 // Factory method to create documents based on the type 8 public static Document getDocument(DocumentType type) { 9 switch (type) { 10 case WORD: 11 return new WordDocument(); 12 case EXCEL: 13 return new ExcelDocument(); 14 default: 15 throw new IllegalArgumentException("Unknown document type: " + type); 16 } 17 } 18}
  • The DocumentType Enum:

    • This enum defines the supported types of documents (WORD and EXCEL). You can easily extend this enum to include additional document types in the future, making the system flexible and scalable.
  • The getDocument Method:

    • This is the factory method that takes a DocumentType as a parameter and returns an instance of the corresponding document class.
    • The switch statement checks the provided document type and creates an instance of WordDocument or ExcelDocument accordingly.
    • If an unsupported or unknown document type is passed, the method throws an IllegalArgumentException. This guards against invalid input, ensuring robustness in your code.
Step 4: Object Creation Using The Factory

To complete our understanding, let's see how to use the Factory Method pattern via a main method. This will help you see how the abstract factory and concrete factory classes work together to create and manage different types of documents.

Java
1public class Main { 2 public static void main(String[] args) { 3 // Create a Word document using the factory method 4 Document wordDoc = DocumentFactory.getDocument(DocumentFactory.DocumentType.WORD); 5 wordDoc.open(); // Outputs: Opening Word Document. 6 7 // Create an Excel document using the factory method 8 Document excelDoc = DocumentFactory.getDocument(DocumentFactory.DocumentType.EXCEL); 9 excelDoc.open(); // Outputs: Opening Excel Document. 10 } 11}

In the main method:

  1. We call the getDocument method of DocumentFactory with DocumentType.WORD to instantiate a WordDocument.
  2. We then call the open method on the WordDocument instance to demonstrate its functionality.

Similarly:

  1. We call the getDocument method of DocumentFactory with DocumentType.EXCEL to instantiate an ExcelDocument.
  2. We then call the open method on the ExcelDocument instance to demonstrate its functionality.

By following these steps and running the main method, you can observe how the Factory Method pattern allows the creation of document objects without needing to know their specific types at compile-time. This encapsulates the instantiation logic within the factory class and promotes flexibility and maintainability in your code.

Why It Matters

The Factory Method pattern is crucial for scenarios where the precise type of the object isn't known until runtime. By mastering this pattern, you'll have the ability to create code that is more modular and easier to extend in the future. For example, consider how you might need different document types in various contexts—using the Factory Method pattern ensures that your code can handle these variations efficiently and without unnecessary duplication.

This pattern offers several key advantages:

  • It encapsulates the object creation process, making the code more maintainable.
  • It decouples client code from specific classes it needs to instantiate, enhancing flexibility.
  • By adhering to the Single Responsibility Principle, it ensures factory classes focus solely on creating objects, promoting cleaner design.
  • It enhances reusability, allowing for the introduction of new object types without modifying existing code.
  • It allows for runtime decisions on class instantiation, enhancing adaptability.

Are you ready to see this in action? Let's begin the practice section and implement the Factory Method pattern together!

Enjoy this lesson? Now it's time to practice with Cosmo!
Practice is how you turn knowledge into actual skills.