What is the simple factory pattern?
The Simple Factory Pattern is a creational design pattern that instantiates different types of objects through a factory class. Based on the parameters passed in, the factory class decides which specific class of object to create. The Simple Factory Pattern is often used to reduce the client code's dependence on specific classes, ensuring that the code is easier to maintain and extend.
In the simple factory pattern, the factory class is responsible for the object creation logic. The client does not need to care about how to create the object, but only needs to provide the necessary parameters to the factory class. Its core idea isExtract object creation from client code, managed by the factory. To learn about other design patterns, click here Design Patterns in Software Engineering: Best Practices for Problem Solving
What problem does it solve?
The simple factory pattern solves the following problems:
- Reduce code duplication: Centralize the instantiation logic into the factory class, reducing the need to repeatedly write code to create objects on the client side.
- Decoupling:The client does not directly depend on specific classes, reducing dependence on implementation details and facilitating subsequent expansion and maintenance.
- Improve code flexibility: Different types of objects can be created dynamically based on the passed in parameters, enhancing the flexibility of the code.
When to use the simple factory pattern?
In the following scenarios, we generally choose the simple factory mode:
- You need to create a large number of objects of different classes, but these objects have the same interface or base class.
- The logic for creating objects is relatively complex, and centralizing it makes the code more maintainable.
- The client does not need to be directly concerned with the details of object creation, it only needs to provide parameters.
Advantages and disadvantages of simple factory pattern
advantage:
- Simplify client code: Encapsulate the object creation logic in the factory class, and the client only needs to interact with the factory.
- Clear code structure: Centrally manage object creation logic, make the code structure clearer, and make maintenance easier.
- Strong scalability: New product types can be added by modifying or extending the factory class without modifying the client code.
shortcoming:
- Violation of the Open-Closed Principle: When adding a new product type, the code of the factory class needs to be modified, which violates the principle of "open for extension, closed for modification".
- Single Responsibility Problem: The factory class assumes the responsibility of creating all objects, which may make it too complex.
Implementation of Simple Factory Pattern in Golang
Let's use a practical example to show how to implement a simple factory pattern in Golang. Suppose we need to create different types of vehicles (such as bicycles, cars, and trucks), all of which implement the same interface Vehicle
.
package main import "fmt" // Vehicle is the interface for all vehicles type Vehicle interface { Drive() string } // Bike bicycles implement the Vehicle interface type Bike struct{} func (b *Bike) Drive() string { return "Bike is being driven" } // Car cars implement the Vehicle interface type Car struct{} func (c *Car) Drive() string { return "Car is being driven" } // Truck trucks implement the Vehicle interface type Truck struct{} func (t *Truck) Drive() string { return "Truck is being driven" } // VehicleFactory is a simple factory class for creating vehicle instances type VehicleFactory struct{} func (vf *VehicleFactory) CreateVehicle(vType string) Vehicle { switch vType { case "bike": return &Bike{} case "car": return &Car{} case "truck": return &Truck{} default: return nil } } func main() { // Create a factory instance factory := &VehicleFactory{} // Create different vehicles through the factory vehicle1 := factory.CreateVehicle("bike") fmt.Println(vehicle1.Drive()) vehicle2 := factory.CreateVehicle("car") fmt.Println(vehicle2.Drive()) vehicle3 := factory.CreateVehicle("truck") fmt.Println(vehicle3.Drive()) }
Golang Implementation Notes
- First we defined
Vehicle
interface, all types of vehicles (Bike
,Car
andTruck
) have implemented this interfaceDrive()
method. - Factory Class
VehicleFactory
ProvidedCreateVehicle()
method, responsible for the incoming type (bike
,car
,truck
) to create the corresponding object instance. - exist
main()
In the function, different types of vehicles are created through the factory class and theirDrive()
method.
Precautions for use in actual development
- Keep the factory class single responsibility: Although the factory class is responsible for creating objects, be careful not to make it too complicated. If there are too many types of products, you can consider using multiple factory classes or improving it through the factory method pattern.
- Avoid overuse: Although the simple factory pattern is convenient, if there are many types of products and the creation logic is complex, the factory class may be too large and difficult to maintain. In this case, you can consider using other design patterns, such as the factory method pattern or the abstract factory pattern.
- Validation of input parameters: In actual use, the parameters of the factory method should be verified to avoid creation failure or program crash due to incorrect input.
- Pay attention to code modifications when expanding:Every time a new type of product is added, the code of the factory class needs to be modified, which violates the open-closed principle. Therefore, if the system has high scalability requirements, you may need to reconsider the design.
Reference Links
After reading this article, you should understand the basic concepts, usage scenarios and implementation methods of the simple factory pattern in Golang. This design pattern can effectively simplify the process of object creation and make the code easier to maintain and extend.