Small knowledge, big challenge! This article is participating in the creation activity of “Essential Tips for Programmers”
preface
When it comes to Java, one sad fact comes to mind: Are you dating someone new every day and still clinging to your single job? (the so-called object oriented programming HHH), this article to learn about the factory mode, get rid of the distress of new objects!
knowledge
Traditional plant
- Abstract classes and subclasses
- Production and use are put together without separation, using the name, and then to produce the corresponding product
public class OrderPizza {
/ / the constructor
public OrderPizza(a) {
Pizza pizza = null;
String orderType; // Type of pizza to order
orderType = getType();
if (orderType.equals("greek")) {
pizza = new GreekPizza();
pizza.setName("Greek Pizza");
} else if (orderType.equals("cheese")) {
pizza = new CheesePizza();
pizza.setName("Cheese Pizza");
} else if (orderType.equals("pepper")) {
pizza = new PepperPizza();
pizza.setName("Pepper Pizza.");
} else {
break;
}
// Output the pizza making process
pizza.prepare();
pizza.bake();
pizza.cut();
pizza.box();
}
Copy the code
Analysis of improved ideas
- It’s okay to change the code, but if we have the code to create Pizza somewhere else, that means we need to change it too, and the code to create Pizza often has multiple places.
- Create Pizza objects in a factory class, so that when we have a new Pizza type, we only need to change the factory class
Simple Factory mode (pass the product name then if-else)
A gigafactory, responsible for producing all kinds of products
- On the basis of the traditional factory, the process of product creation is encapsulated into a factory class to achieve the separation of production and use
Interface class/Abstract class
packageCom.melo.design.factory mode. Simple factory model;public interface Shape {
void draw(a);
}
Copy the code
The subclass product
packageCom.melo.design.factory mode. Simple factory model;public class Circle implements Shape{
@Override
public void draw(a) {
System.out.println("Circle"); }}Copy the code
The factory class
packageCom.melo.design.factory mode. Simple factory model;public class ShapeFactory {
public static Shape getShape(String shape){
if("Circle".equals(shape)){
return new Circle();
}else if("Triangle".equals(shape)){
return new Triangle();
}
return null; }}Copy the code
The caller
packageCom.melo.design.factory mode. Simple factory model;public class Main {
public static void main(String[] args) {
Shape circle = ShapeFactory.getShape("Circle"); circle.draw(); }}Copy the code
disadvantages
To summarize, the simple factory pattern is to have a single factory class responsible for building all objects. Let the factory produce whatever product the caller needs. Its disadvantages are also obvious:
- One is that if too many products need to be produced, this pattern will lead to the factory class being too large and taking on too many responsibilities, becoming a super class. When apple’s production process needs to be modified, the factory needs to be modified. When the pear production process needs to be modified, the factory also needs to be modified. That is, this class has more than one cause for modification. It violates the single responsibility principle.
- The second is that when new products are produced, new branches must be added to the factory class. The open closed principle tells us that classes should be closed to modifications. We want to add new classes when we add new functionality, not modify existing classes, so this violates the open close principle.
Factory method pattern
- In the factory method pattern, instead of providing a single factory class to create all objects, we provide different factories for different objects. That is, each object has a factory corresponding to it.
- The factory method makes instantiation of a class defer to subclasses!!
The simple factory used to be one factory, responsible for producing all products, but now it has to be changed to one factory for each object, and one factory is only responsible for producing one product
advantages
- Thus we have solved the problem of single responsibility mentioned above, each plant is responsible for producing only one product
- At the same time, it also solves the open and closed principle. Every time we need to add a new product, we only need to add a new factory class, instead of modifying the original factory class
disadvantages
- Every time a product is added, a concrete class and object implementation factory need to be added, doubling the number of classes in the system, increasing the complexity of the system to a certain extent, but also increasing the dependence of the system concrete class. This is not a good thing.
Each product corresponds to a factory class, and then products of the same class, such as fruit classes, are abstracted into a fruit factory class to implement his create method
MyDemo
Fruit interface
package com.melo.mydesign.Factory.FactoryMethod.Product;
// The product is only used, not created
public interface Fruit {
void eat(a);
}
Copy the code
Specific fruit category
package com.melo.mydesign.Factory.FactoryMethod.Product;
public class Apple implements Fruit {
@Override
public void eat(a) {
System.out.println("Eat an apple"); }}Copy the code
package com.melo.mydesign.Factory.FactoryMethod.Product;
public class Pear implements Fruit {
@Override
public void eat(a) {
System.out.println("Eating pears"); }}Copy the code
Fruit factory interface
package com.melo.mydesign.Factory.FactoryMethod.Factory;
import com.melo.mydesign.Factory.FactoryMethod.Product.Fruit;
public interface FruitFactory {
Fruit createFruit(a);
}
Copy the code
Concrete fruit factory implementation subclass
package com.melo.mydesign.Factory.FactoryMethod.Factory;
import com.melo.mydesign.Factory.FactoryMethod.Product.Apple;
import com.melo.mydesign.Factory.FactoryMethod.Product.Fruit;
public class AppleFactory implements FruitFactory {
@Override
public Fruit createFruit(a) {
return newApple(); }}Copy the code
package com.melo.mydesign.Factory.FactoryMethod.Factory;
import com.melo.mydesign.Factory.FactoryMethod.Product.Fruit;
import com.melo.mydesign.Factory.FactoryMethod.Product.Pear;
public class PearFactory implements FruitFactory {
@Override
public Fruit createFruit(a) {
return newPear(); }}Copy the code
The specific use
package com.melo.mydesign.Factory.FactoryMethod;
import com.melo.mydesign.Factory.FactoryMethod.Factory.AppleFactory;
import com.melo.mydesign.Factory.FactoryMethod.Factory.FruitFactory;
import com.melo.mydesign.Factory.FactoryMethod.Product.Fruit;
public class Consumer {
public static void main(String[] args) {
// The user does not need to know which class is being produced
FruitFactory appleFactory = newAppleFactory(); Fruit apple = appleFactory.createFruit(); apple.eat(); }}Copy the code
Abstract Factory pattern
- The factory method model, as more and more products are produced, there will be more and more product categories and product factories, can we separate one product from the other into a product family?
This means that instead of having a product factory for every product there’s a product factory for a class of products
Take the newbie example (feel authoritative)
UML
- First of all, from the user’s point of view, to produce a product, we must first find the product factory where the product is located
How do I find the product factory? A FactoryProducer also needs someone to create it. A FactoryProducer is also a factory that deals with multiple products
- And then you get the specific product category factory, you have to produce the specific product, same as above (if-else)
- All that remains is the product and the parent product. See the implementation code below
We can see that the Shape factory is responsible for multiple shapes, so we can go back to the simple factory, one factory handles multiple products (we need to pass string names and then if-else)
Abstract factory and concrete product factory (note that factory class methods need to be defined)
See the implementation of the subclass
- You can see that the Shape product class factory also implements the Color method, just return null
FactoryProducer also has to deal with multiple factors, including Shape and Color
The specific use
MyDemo
Abstract product class factory
package com.melo.mydesign.Factory.AbstractFactory.Factory;
import com.melo.mydesign.Factory.AbstractFactory.Product.Car.Car;
import com.melo.mydesign.Factory.AbstractFactory.Product.Fruit.Fruit;
public interface AbstractFactory {
Fruit createFruit(String fruitName);
Car createCar(String carName);
}
Copy the code
Specific product factory –Car
package com.melo.mydesign.Factory.AbstractFactory.Factory;
import com.melo.mydesign.Factory.AbstractFactory.Product.Car.Audi;
import com.melo.mydesign.Factory.AbstractFactory.Product.Car.BMW;
import com.melo.mydesign.Factory.AbstractFactory.Product.Car.Car;
import com.melo.mydesign.Factory.AbstractFactory.Product.Fruit.Fruit;
public class CarFactory implements AbstractFactory{
@Override
public Fruit createFruit(String fruitName) {
return null;
}
public Car createCar(String carName){
if(carName.equalsIgnoreCase("BMW")) {return new BMW();
}else if(carName.equalsIgnoreCase("Audi")) {
return new Audi();
}
return null; }}Copy the code
Specific product factory –Fruit
package com.melo.mydesign.Factory.AbstractFactory.Factory;
import com.melo.mydesign.Factory.AbstractFactory.Product.Car.Car;
import com.melo.mydesign.Factory.AbstractFactory.Product.Fruit.Pear;
import com.melo.mydesign.Factory.AbstractFactory.Product.Fruit.Apple;
import com.melo.mydesign.Factory.AbstractFactory.Product.Fruit.Fruit;
public class FruitFactory implements AbstractFactory {
public Fruit createFruit(String fruitName){
if(fruitName.equalsIgnoreCase("Apple")) {return new Apple();
}else if(fruitName.equalsIgnoreCase("Pear")) {
return new Pear();
}
return null;
}
@Override
public Car createCar(String carName) {
return null; }}Copy the code
FactoryProducer– The object responsible for producing product-like factories
package com.melo.mydesign.Factory.AbstractFactory.Factory;
public class FactoryProducer {
public static AbstractFactory produceFactory(String factoryName){
if(factoryName.equalsIgnoreCase("Fruit")) {return new FruitFactory();
}else if (factoryName.equalsIgnoreCase("Car")) {return new CarFactory();
}
return null; }}Copy the code
Car product interface
package com.melo.mydesign.Factory.AbstractFactory.Product.Car;
// The product is only used, not created
public interface Car {
void eat(a);
}
Copy the code
Car product implementation class
package com.melo.mydesign.Factory.AbstractFactory.Product.Car;
public class BMW implements Car {
@Override
public void eat(a) {
System.out.println("BMW"); }}Copy the code
Fruit products
package com.melo.mydesign.Factory.AbstractFactory.Product.Fruit;
// The product is only used, not created
public interface Fruit {
void eat(a);
}
Copy the code
Fruit class implementation class
package com.melo.mydesign.Factory.AbstractFactory.Product.Fruit;
import com.melo.mydesign.Factory.AbstractFactory.Product.Fruit.Fruit;
public class Pear implements Fruit {
@Override
public void eat(a) {
System.out.println("Eating pears"); }}Copy the code
consumers
package com.melo.mydesign.Factory.AbstractFactory;
import com.melo.mydesign.Factory.AbstractFactory.Factory.AbstractFactory;
import com.melo.mydesign.Factory.AbstractFactory.Factory.FactoryProducer;
import com.melo.mydesign.Factory.AbstractFactory.Product.Car.Car;
public class Consumer {
public static void main(String[] args) {
AbstractFactory carFactory = FactoryProducer.produceFactory("Car");
Car bmw = null;
if(carFactory ! =null) {
bmw = carFactory.createCar("BMW");
}
if(bmw ! =null) { bmw.eat(); }}}Copy the code
disadvantages
- It no longer conforms to the open and closed principle, because the essence is from the simple factory to upgrade, it is back to a product factory, need to deal with the problems of multiple products, ** need if-else **
Every time we add a product class factory, we need to abstract the new method from the product class factory AbstractFactory, and all of its subclasses also need to implement the new method. Crucially, we also need to modify the if-else in FactoryProducer to break the open and close principle. All subclasses need to change!!
conclusion
- A small factory model, the previous learned several major principles: open and close principle, rely on the reversal principle (good useAbstract interfaceRather than implement).
- Fruit apple = new Apple(); Fruit apple = new Apple(); Apple = new Apple();
- And if the production process is complicated, such as apple also need all kinds of processing, you need to encapsulate the process of creating, not exposed to the user, then you need to use a special factory for packaging, the outside world only need from inside the factory, a simple word “apple” string, it turned to the simple factory pattern
- Then we found a simple factory class, called simple, but dealing with a variety of products, and every time we added a new product, we had to change the if-else code block, which didn’t match the open and close principle
- The factory method pattern is introduced Let each product due to a product factory, specialized factory to produce a product, a factory is responsible for the production of a product, only to satisfy the single responsibility principle, every time new products at the same time, only need to add a product factory, the need to modify the original factory, and solved the problem of the open closed principle
- However, with the increasing number of products, if only one factory is responsible for one product, the number of factories may increase. Moreover, these products may have some connection before, for example, they are all fruits, so why not separate a fruit factory to produce various fruits
See here may have careful readers found that a factory is responsible for the production of multiple products, that seems to be back to the simple factory model, inconsistent with the open and close principle and single responsibility, yes, the abstract factory model is actually the simple factory upgrade version!