Design patterns are essential tools in a software developer’s toolkit, website link providing proven solutions to recurring design problems. Among these, the Factory Method Pattern stands out as a fundamental creational pattern that promotes loose coupling and adheres to the Open/Closed Principle. For students tackling Java assignments involving object creation, understanding this pattern is crucial. This article provides a detailed walkthrough of the Factory Method Pattern, complete with UML diagrams and practical Java code examples to help you ace your next assignment.
What is the Factory Method Pattern?
The Factory Method Pattern defines an interface for creating an object but allows subclasses to decide which class to instantiate. Unlike the Simple Factory (which is not a genuine design pattern but a programming idiom), the Factory Method Pattern delegates the instantiation logic to subclasses, promoting flexibility and extensibility.
Key benefits include:
- Eliminates tight coupling between client code and concrete product classes
- Supports the Open/Closed Principle (classes open for extension, closed for modification)
- Enables polymorphic object creation
- Simplifies adding new product types without changing existing client code
Understanding the Participants
Before diving into code, let’s examine the core components of the Factory Method Pattern:
- Product (Interface): Declares the interface for objects the factory method creates
- ConcreteProduct (Class): Implements the Product interface
- Creator (Abstract Class): Declares the factory method that returns Product objects
- ConcreteCreator (Class): Overrides the factory method to return an instance of ConcreteProduct
UML Diagram Representation
text
+----------------+ +----------------+
| <<abstract>>| | <<interface>>|
| Creator | | Product |
+----------------+ +----------------+
| +factoryMethod()|-------->| +operation() |
| : Product | +----------------+
+----------------+ △
△ |
| |
| +----------------+
+----------------+ | ConcreteProduct|
| ConcreteCreator| +----------------+
+----------------+ | +operation() |
| +factoryMethod()|----------->+----------------+
| : Product |
+----------------+
In this diagram, the Creator class depends only on the Product interface, not on concrete implementations. ConcreteCreator provides the specific product instance.
Real-World Scenario: Document Processing System
Let’s implement a document processing system where different types of documents (PDF, Word, HTML) need to be created and opened. about his This is a common assignment scenario in Java courses.
Step 1: Define the Product Interface
java
public interface Document {
void open();
void save();
void close();
String getInfo();
}
Step 2: Implement Concrete Products
java
public class PdfDocument implements Document {
@Override
public void open() {
System.out.println("Opening PDF document with Adobe Reader...");
}
@Override
public void save() {
System.out.println("Saving PDF document...");
}
@Override
public void close() {
System.out.println("Closing PDF document...");
}
@Override
public String getInfo() {
return "PDF Document (Portable Document Format)";
}
}
public class WordDocument implements Document {
@Override
public void open() {
System.out.println("Opening Word document with Microsoft Word...");
}
@Override
public void save() {
System.out.println("Saving Word document...");
}
@Override
public void close() {
System.out.println("Closing Word document...");
}
@Override
public String getInfo() {
return "Word Document (Microsoft Word Format)";
}
}
public class HtmlDocument implements Document {
@Override
public void open() {
System.out.println("Opening HTML document with web browser...");
}
@Override
public void save() {
System.out.println("Saving HTML document...");
}
@Override
public void close() {
System.out.println("Closing HTML document...");
}
@Override
public String getInfo() {
return "HTML Document (Web Page Format)";
}
}
Step 3: Create the Abstract Creator
java
public abstract class DocumentCreator {
// The factory method
public abstract Document createDocument();
// Common operations that use the factory method
public void processDocument() {
Document doc = createDocument();
doc.open();
doc.save();
doc.close();
}
public void displayDocumentInfo() {
Document doc = createDocument();
System.out.println("Document Info: " + doc.getInfo());
}
}
Step 4: Implement Concrete Creators
java
public class PdfCreator extends DocumentCreator {
@Override
public Document createDocument() {
return new PdfDocument();
}
}
public class WordCreator extends DocumentCreator {
@Override
public Document createDocument() {
return new WordDocument();
}
}
public class HtmlCreator extends DocumentCreator {
@Override
public Document createDocument() {
return new HtmlDocument();
}
}
Step 5: Client Code Demonstration
java
public class DocumentApplication {
public static void main(String[] args) {
// Process different document types polymorphically
DocumentCreator creator;
// Process PDF
creator = new PdfCreator();
System.out.println("=== Processing PDF ===");
creator.processDocument();
creator.displayDocumentInfo();
System.out.println("\n=== Processing Word ===");
creator = new WordCreator();
creator.processDocument();
creator.displayDocumentInfo();
System.out.println("\n=== Processing HTML ===");
creator = new HtmlCreator();
creator.processDocument();
creator.displayDocumentInfo();
// Demonstrate flexibility: adding new document type
System.out.println("\n=== Adding Excel Support ===");
// To add Excel, we only need to create ExcelDocument and ExcelCreator
// without modifying existing code!
}
}
Output
text
=== Processing PDF === Opening PDF document with Adobe Reader... Saving PDF document... Closing PDF document... Document Info: PDF Document (Portable Document Format) === Processing Word === Opening Word document with Microsoft Word... Saving Word document... Closing Word document... Document Info: Word Document (Microsoft Word Format) === Processing HTML === Opening HTML document with web browser... Saving HTML document... Closing HTML document... Document Info: HTML Document (Web Page Format)
Advanced Variations for Assignments
Parameterized Factory Method
Sometimes you need to decide which product to create based on a parameter:
java
public abstract class ParameterizedCreator {
public abstract Document createDocument(String type);
public void processByType(String type) {
Document doc = createDocument(type);
if (doc != null) {
doc.open();
doc.save();
doc.close();
}
}
}
public class FlexibleDocumentCreator extends ParameterizedCreator {
@Override
public Document createDocument(String type) {
switch(type.toLowerCase()) {
case "pdf": return new PdfDocument();
case "word": return new WordDocument();
case "html": return new HtmlDocument();
default: throw new IllegalArgumentException("Unknown document type");
}
}
}
Generic Factory Method with Reflection
java
public class ReflectionDocumentCreator extends DocumentCreator {
private Class<? extends Document> documentClass;
public ReflectionDocumentCreator(Class<? extends Document> docClass) {
this.documentClass = docClass;
}
@Override
public Document createDocument() {
try {
return documentClass.getDeclaredConstructor().newInstance();
} catch (Exception e) {
throw new RuntimeException("Failed to create document", e);
}
}
}
Common Pitfalls to Avoid in Assignments
- Confusing Simple Factory with Factory Method: Remember, Factory Method uses inheritance and polymorphism, while Simple Factory uses a single class with conditional logic.
- Making the Creator Concrete: The Creator should be abstract to enforce subclass implementation of the factory method.
- Forgetting the Product Interface: Always program to interfaces, not concrete classes.
- Overcomplicating Simple Scenarios: If object creation logic is simple and won’t change, consider simpler alternatives.
When to Use the Factory Method Pattern
Consider this pattern when:
- A class cannot anticipate the type of objects it must create
- A class wants its subclasses to specify the objects it creates
- You want to localize the knowledge of which concrete class is created
- You’re writing a framework that needs to work with multiple product types
Conclusion
The Factory Method Pattern is a powerful tool for creating flexible, maintainable Java applications. By understanding its structure through UML diagrams and implementing it in code, you’re well-equipped to handle assignments that require polymorphic object creation. Remember that mastering design patterns takes practice – try extending our document example with new product types or experiment with parameterized factory methods.
For your next Java assignment, analyze whether the Factory Method Pattern fits your requirements. If you need to decouple client code from concrete classes while maintaining the flexibility to add new product types, my link this pattern provides an elegant solution that will impress your instructors and improve your software design skills.