As we all know, in real life the factory is used to produce a variety of products, while in programming, the factory is a place for production examples. Every time we create objects in Java, we need to create an instance of a type with new. However, in a complex system, the objects created also need to be determined by external requirements. For example, if a fruit store serves fruit, we might write:

Public static void main(String[] args) {if (customer). Ask for taste ().equals(" sweet ")) {watermelon melon = new watermelon (); } else if (customer. Equals () {orange = new orange (); } else if ... }}Copy the code

This may seem like a simple conditional judgment, but there are two main problems with this:

  1. Code duplication: do the same for the rest of the fruit store or the rest of the fruit store
  2. Coupling degree is high: fruit class is included to a large extent to the fruit store class, as long as the modification of the fruit class, the store class also want to be all modified

Degree of coupling: the code of a class contains the logic of other classes, including many degrees of coupling is high, and easy to affect each other.

So we need to use the factory pattern to solve this problem.

1. Simple factory mode

There are two main steps to achieve a simple factory:

  1. Abstract our specific product resources (watermelon, orange) into one thing (fruit)
  2. Create a new factory class and give the factory the job of producing specific examples (melons, oranges, etc.)

In the “fruit supply” example above, we can abstract the various fruits into an interface or abstract class, and then produce them through the fruit factory class, making the class diagram as follows:

The core is the fruit factory class, the implementation is as follows:

/** * FruitFactory */ public class FruitFactory {/** * @return FruitFactory */ public static Fruit get(Customer) customer) { Fruit fruit = null; If (customer.getflavor ().equals(" sweet ")) {fruit = new flavor (); } else if (customer.getflavor ().equals(" customer.getflavor ")) {fruit = new Orange(); } else if (customer.getflavor ().equals()) {fruit = new Apple(); } return fruit; }}Copy the code

Fruit abstract class

import lombok.Getter; import lombok.Setter; / / @setter@getter public abstract class Fruit {/** * Fruit name */ private String name; }Copy the code

watermelon

import lombok.Getter; import lombok.Setter; /** * Watermelon */ @getter @setter public class Watermelon extends Fruit {/** * Watermelon */ private Boolean cooked; }Copy the code

apple

import lombok.Getter; import lombok.Setter; / * * * * / classification Apple @ Getter @ Setter public class extends Apple Fruit {/ * * * * / private sweetness int sweetness. }Copy the code

The oranges

import lombok.Getter; import lombok.Setter; Public class Fruit extends Fruit {/** * acidity */ private int acidity; }Copy the code

The customer

import lombok.Getter; import lombok.Setter; /** * Customer class */ @getter@setter public class Customer {/** * name */ private String name; / / private String flavor; }Copy the code

Ok, now the fruit store wants to sell the fruit, the fruit store can now call the factory directly:

Public static FruitShop {FruitShop, FruitShop, FruitShop, FruitShop, FruitShop, FruitShop, FruitShop, FruitShop, FruitShop sellFruit(Customer customer) { return FruitFactory.get(customer); }}Copy the code

You can see that the simple factory pattern also creates objects based on external requirements, but now the responsibility is more clear and the creation of objects is left to the factory. The fruit store only needs to tell the factory what the guests want to eat, and get the corresponding fruit from the factory to the guests, and do not need to know what the specific fruit.

Since all fruits have the same property, “fruit name,” fruits are represented by abstract classes that hold properties common to different fruits. Otherwise, you can use the interface to represent the fruit, depending on the situation.

2. Abstract factory pattern

The simple factory model above only involves the production of one kind of product, but what about multiple kinds of products?

For example, the fruit store is now selling fruit tea. Do we need to build a new fruit tea factory and link it with the fruit store? Of course not. This will lead to fruit stores and various factories coupling degree is too tight, not conducive to expansion.

As the name suggests, the abstract factory pattern abstracts the factories that generate the instances further. Colloquially, it is necessary to build “factories that produce factories”.

First of all, Fruit and Fruit tea are called FruitFood (FruitFood), so we want to abstract two factories (Fruit factory, Fruit tea factory) into the factory interface or abstract class (FruitFood factory, FruitFoodFactory), and through the factory structure class according to the demand to create a factory and then produce products.

The class diagram is as follows:

Fruit food factory interface code

*/ public interface FruitFoodFactory {/** * @param customer ** @return FruitFoodFactory instance */ Fruit getFruit(Customer customer); /** ** @param customer ** @return customer */ Drink getDrink(customer customer); }Copy the code

Fruit factory

/** * FruitFactory */ public class FruitFactory implements FruitFoodFactory {@override public FruitFactory implements fruitfruit (Customer Customer)  { Fruit fruit = null; If (customer.getflavor ().equals(" sweet ")) {fruit = new flavor (); } else if (customer.getflavor ().equals(" customer.getflavor ")) {fruit = new Orange(); } else if (customer.getflavor ().equals()) {fruit = new Apple(); } return fruit; } @Override public Drink getDrink(Customer customer) { return null; }}Copy the code

Since the fruit factory does not produce fruit tea but the fruit factory implements the interface to the fruit food factory, there is also a getDrink method. Leave it blank and return null.

The fruit tea factory is similar to the fruit factory in that it implements the fruit food factory interface and completes the getDrink method, but leaves the getFruit method blank and returns null.

Then there’s the factory build class (the factory that makes the factory)

/** * FruitFoodFactoryBuilder */ public class FruitFoodFactoryBuilder {/** * @param type * @return factoryBuilder */ public FruitFoodFactory buildFactory(String type) { FruitFoodFactory factory = null; If (type.equals(" FruitFactory ")) {factory = new FruitFactory(); } else if (type.equals(" DrinkFactory ")) {factory = new DrinkFactory(); } return factory; }}Copy the code

The rest of the basic classes are not listed one by one.

Similarly, in the fruit store, you only need to call the factory construction class to build the corresponding factory, and then call the corresponding factory corresponding method to generate the product.

Visible simple factory, the fruit store and the factory is associated, so reduce the coupling degree of the fruit store and the fruit, the fruit store does not need to know what fruit, just the corresponding fruit can be obtained; In the abstract factory pattern, the fruit store is associated with the factory structure class, so not only does the fruit store not need to know what fruit it needs, but it also does not need to know which factory it needs to go to, further reducing the coupling.

As you can see, the abstract factory pattern is a further abstraction based on the simple factory pattern.