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!