Key Takeaways
- The Factory Method design pattern is utilized to define a runtime interface for creating an object, without necessarily knowing what kind of object it creates or how to create it. It is often used when a class cannot anticipate the type of objects it needs to create beforehand, or when a class wants its subclasses to specify the objects it creates.
- The Factory Method pattern is beneficial for abstracting the creation of an object away from its actual implementation. This allows for changes in components or technologies without affecting the rest of the application, as the logic to create a specific object type is encapsulated within the class itself.
- The Factory Method pattern can also be applied to situations where factories use other factories to create objects. This further abstracts the creation process and allows for a more modular design, as each factory is responsible for creating a specific part and the main factory assembles these parts to create the final product.
The Factory Method
The Factory Method pattern is a design pattern used to define a runtime interface for creating an object. It’s called a factory because it creates various types of objects without necessarily knowing what kind of object it creates or how to create it. Here’s an example of how the Factory Pattern works. Assume you have aProductFactory
class which creates a new type of product:
<?php
class ProductFactory
{
public static function build($type) {
// assumes the use of an autoloader
$product = "Product_" . $type;
if (class_exists($product)) {
return new $product();
}
else {
throw new Exception("Invalid product type given.");
}
}
}
By defining build()
as a factory method, you now have an interface through which you can create different products on the fly.
<?php
// build a new Product_Computer type
$myComputer = ProductFactory::build("Computer");
// build a new Product_Tablet type
$myTablet = ProductFactory::build("Tablet");
The Factory Method pattern is generally used in the following situations:
- A class cannot anticipate the type of objects it needs to create beforehand.
- A class requires its subclasses to specify the objects it creates.
- You want to localize the logic to instantiate a complex object.
<?php
class Product_MobileDevice
{
private $components;
public function __construct() {
// this device uses a 7" LCD
$this->addComponent(ProductFactory::build("LCD", 7));
// and features an 1GHz ARM processor
$this->addComponent(ProductFactory::build("CPU_ARM", 1));
}
...
}
// build a new Product_MobileDevice type
$myDevice = ProductFactory::build("MobileDevice");
$myDevice->use();
The logic to create a Product_MobileDevice
object has been encapsulated into the class itself. If you want to exchange the 7″ LCD screen with a 10″ Touch_Screen later, you can make the isolated change in the MobileDevice class without affecting the rest of your application.
Factories Using Other Factories
Because the instantiation of an object is encapsulated, it could also use factories itself. To further expand on the idea of abstract object creation, let’s use a non-software engineering analogy. An automotive factory manufactures vehicles of a specific make, model, and color, but it may not produce all the necessary parts itself that are required to build the vehicle. In other words, it delegates the production of these parts out to other factories which it then uses to build new vehicles. Under this scenario, a vehicle factory might look like this:<?php
class VehicleFactory
{
public static function build($make, $model, $color) {
$vehicle = new Vehicle;
// vehicle needs a chassis which is produced by another factory
$vehicle->addPart(VehicleChassisFactory::build($make, $model));
// needs an engine built by someone else
$vehicle->addPart(VehicleEngineFactory::build($make, $model));
// it needs a bodykit made by another factory
$vehicle->addPart(VehicleBodyFactory::build($make, $model, $color));
// and interiors are made by... you guessed it, someone else
$vehicle->addPart(VehicleInteriorFactory::build($make, $model, $color));
// ...add more parts
return $vehicle;
}
}
// build a new white VW Amarok
$myCar = VehicleFactory::build("Volkswagon", "Amarok", "white");
$myCar->drive();
Voilà! A shiny new car. The VehicleFactory
class produces a vehicle of a specified make, model and color, but acquired the various parts produced by other factory methods.
Summary
In this article you’ve learned how the Factory Method pattern can be used to localize the construction of different objects and to allow you to create objects without knowing specifically what type you’ll need beforehand. You also saw also factory methods can use other factory methods to create objects objects and define what objects they produce. Image via yuminglin / ShutterstockFrequently Asked Questions (FAQs) about the Factory Method Design Pattern
What is the main difference between the Factory Method and Simple Factory patterns?
The Factory Method and Simple Factory patterns are both creational design patterns, but they differ in their implementation. The Simple Factory encapsulates object creation in one method, and this method typically uses a switch statement or similar conditional logic to determine which product class to instantiate. On the other hand, the Factory Method pattern uses inheritance and relies on subclasses to handle the object creation. This allows the Factory Method pattern to be more flexible and extendable, as new product classes can be added without modifying the existing code.
How does the Factory Method pattern support the Open-Closed Principle?
The Open-Closed Principle states that software entities should be open for extension but closed for modification. The Factory Method pattern supports this principle by allowing new types of products to be created and added to the system without changing the existing client code. This is achieved by defining a common interface for the factories and products, and using subclasses to implement the specific factories and products.
When should I use the Factory Method pattern?
The Factory Method pattern is particularly useful when a class cannot anticipate the type of objects it needs to create, or when a class wants its subclasses to specify the objects it creates. It’s also beneficial when classes delegate responsibility to one of several helper subclasses, and you want to localize the knowledge of which helper subclass is the delegate.
Can the Factory Method pattern be used with other design patterns?
Yes, the Factory Method pattern can be used in conjunction with other design patterns. For example, it can be used with the Prototype pattern when the factory methods in the prototype’s subclasses use these operations to clone the prototype’s objects. It can also be used with the Template Method pattern, where the template method calls a factory method to create a product object.
What are the benefits of using the Factory Method pattern?
The Factory Method pattern provides several benefits. It provides a way to encapsulate the creation of objects, which can simplify code and make it easier to maintain. It also promotes loose coupling by eliminating the need for a class to have knowledge of the actual classes it needs to create. Furthermore, it supports the addition of new types of products without changing the existing client code.
Are there any drawbacks to using the Factory Method pattern?
While the Factory Method pattern has many benefits, it also has a few drawbacks. It can lead to more complexity in the code due to the introduction of additional classes and interfaces. It can also result in more difficult debugging, as the behavior is distributed across multiple classes. Additionally, if the products need to be extended, the corresponding factory may also need to be extended.
How does the Factory Method pattern handle changes to the product classes?
The Factory Method pattern handles changes to the product classes by encapsulating the creation process in the factory method. If a product class changes, only the corresponding factory method needs to be updated. This encapsulation makes the code more robust and easier to maintain.
Can the Factory Method pattern be used in multi-threaded applications?
Yes, the Factory Method pattern can be used in multi-threaded applications. However, care must be taken to ensure that the factory methods are thread-safe. This can be achieved by using synchronization mechanisms such as locks or semaphores.
How does the Factory Method pattern relate to SOLID principles?
The Factory Method pattern is closely related to two of the SOLID principles: the Open-Closed Principle and the Dependency Inversion Principle. The Open-Closed Principle is supported as the pattern allows new types of products to be added without modifying existing code. The Dependency Inversion Principle is adhered to as high-level modules (the abstract factory and product classes) do not depend on low-level modules (the concrete factory and product classes). Instead, they all depend on abstractions.
Can the Factory Method pattern be used in languages other than Java?
Yes, the Factory Method pattern can be implemented in any object-oriented programming language that supports inheritance and polymorphism. This includes languages such as C++, C#, Python, and Ruby. The implementation details may vary slightly due to the differences in language syntax and features, but the underlying concept remains the same.
Ignatius Teo is a freelance PHP programmer and has been developing n-tier web applications since 1998. In his spare time he enjoys dabbling with Ruby, martial arts, and playing Urban Terror.