This article introduces the factory pattern of 23 design patterns.

define

  • Factory patterns are divided into simple factories (not strictly design patterns), factory methods, and abstract factories. Is of the create type and is used to decouple the created object.
  • Factory method: defines an interface for creating objects, with subclasses to implement the system’s object creation operations.
  • Abstract factory: Provides an interface for creating families of related or dependent objects without explicitly specifying concrete classes.

Simple factory

If you run a restaurant and only have one kind of fried rice at the beginning, the way to generate it is very simple, just create it.

public class MyRestaurant { public FriedRice getFriedRice(){ FriedRice rice = new FriedRice(); rice.perpare(); / / prepare rice. Fry (); / / Fried rice. Loading (); // Return rice; }}Copy the code

As business is getting better and better, to promote new products, it is necessary to add a variety of fried rice, for example: shark fin fried rice, can be judged according to the type of incoming.

public class MyRestaurant { public FriedRice getFriedRice(String type) { FriedRice rice = null; Switch (type) {case "sharkFin": // New SharkFinFriedRice(); break; Case "beef":// Rice = new BeefFriedRice(); break; Case "Yangzhou ": // Yangzhou fried rice = new YangzhouFriedRice(); break; } rice.perpare(); / / prepare rice. Fry (); / / Fried rice. Loading (); // Return rice; }}Copy the code

If I need to add and remove menus according to market conditions, I need to change the judgment in the method, violating the open and close principle, and if I open a second restaurant, I will have duplicate code. At this point, you want to leave the invariant and pull out the variable and hand it over to other classes. Therefore, the method of creating the object is taken away.

Public class SimpleRiceFactory {static FriedRice createFriedRice(String type){FriedRice rice = null; switch (type) { case "sharkFin": rice = new SharkFinFriedRice(); break; case "beef": rice = new BeefFriedRice(); break; case "yangzhou": rice = new YangzhouFriedRice(); break; } return rice; } } public class MyRestaurant { public FriedRice getFriedRice(String type) { FriedRice rice = SimpleRiceFactory.createFriedRice(type); // Give a simple factory to create rice.perpare(); rice.fry(); rice.loading(); return rice; }}Copy the code

The class diagram

In summary, a simple factory is more of a programming habit than a creation method.

The factory method

If you want to open more than one branch, each branch will make the same fried rice, but there are regional differences in taste preferences. In the simple factory style, you can create as many factories as there are restaurants. So I want to tie the creation to the hotel, but still have some flexibility. For example, restaurants can be allowed to create their own fried rice, but the process is fixed. You can create an abstract class for a restaurant and let the branch store inherit the class and implement different flavors by itself.

Public abstract class Restaurant {// Create object public abstract FriedRice createFriedRice(String type); Public FriedRice getFriedRice(String type) {FriedRice rice = createFriedRice(type); rice.perpare(); rice.fry(); rice.loading(); return rice; } } public class MyRestaurant extends Restaurant{ @Override public FriedRice createFriedRice(String type) { FriedRice rice = null; switch (type) { case "sharkFin": rice = new SharkFinFriedRice(); break; case "beef": rice = new BeefFriedRice(); break; case "yangzhou": rice = new YangzhouFriedRice(); break; } return rice; }}Copy the code

describe

  • Schema name: FACTORY METHOD
  • Type: Class creation pattern
  • Intent: Define an interface for creating objects and let subclasses decide which class to instantiate. The Factory Method delays the instantiation of a class to its subclasses.
  • Applicability:
    • When a class wants its subclasses to specify the objects it creates.
    • When a class does not know the class of the object it must create.
  • Effect:
  • Advantages:
    • Users only need to know the name of the specific factory to get the product they want, without knowing the specific creation process of the product.
    • Strong scalability, new products only need to add factory class.
  • Disadvantages:
    • It is easy to have too many classes and add complexity.

The class diagram

Case class diagram

The factory method pattern defines an interface for creating objects, and the subclass decides which class to instantiate. The factory method lets the class defer instantiation to the subclass.

Factory method class diagram

The term interface refers to both abstract classes and interfaces

  1. Abstract Factory: Provides an interface to create a product through which the caller accesses the Factory method create() of the concrete Factory to create the product.
  2. ConcreteFactory: Abstract methods in abstract factories are implemented to create concrete products.
  3. Abstract Product: Defines the specification of the Product, describing the main features and functions of the Product.
  4. Concreteproducts: Interfaces that implement abstract product roles are created by concrete factories and correspond to concrete factories.

The abstract factory

In the restaurant that we analyzed, we know that every dish is actually a combination of these ingredients, and the ingredients vary from place to place. The original fried rice object only described the behavior, but now with attributes, it should also be encapsulated, otherwise it will lead to too many associated classes, which is not conducive to maintenance, and does not conform to the principle of dependency inversion.

So you need to modify the FriedRice class first, adding the corresponding attributes and product classes

public abstract class FriedRice {

    Rice rice;

    Seasoning seasoning;

    Meat meat;

    abstract void perpare();

    abstract void fry();

    abstract void loading();


}
Copy the code

Add an abstract factory for creating FriedRice

Public interface AbstractFriedRiceFactory {public Rice createRice(); public Seasoning createSeasoning(); public Meat createMeat(); } / / implementation class 1 public class SpicyBeefFriedRiceFactory implements AbstractFriedRiceFactory {@ Override public Rice createRice ()  { return new NortheastRice(); } @Override public Seasoning createSeasoning() { return new LaoGanMa(); } @Override public Meat createMeat() { return new Beef(); }} / / implementation class 2 public class JueweiBeefFriedRiceFactory implements AbstractFriedRiceFactory {@ Override public Rice createRice() { return new WuchangRice(); } @Override public Seasoning createSeasoning() { return new JwSeasoning(); } @Override public Meat createMeat() { return new Beef(); }}Copy the code

Create the FriedRice implementation class and pass in the factory object you want to implement

public class BeefFriedRice extends FriedRice { AbstractFriedRiceFactory factory; Public JueweiBeefFriedRice(AbstractFriedRiceFactory factory) {this.factory = factory; } @Override void perpare() { meat = factory.createMeat(); seasoning = factory.createSeasoning(); rice = factory.createRice(); }}Copy the code

Finally revise the hotel code

public class MyRestaurant extends Restaurant{ @Override public FriedRice createFriedRice(String type) { FriedRice rice =  null; / / by modifying the incoming factory class to change, but can be by external incoming / / AbstractFriedRiceFactory factory = new JueweiBeefFriedRiceFactory (); AbstractFriedRiceFactory factory = new SpicyBeefFriedRiceFactory(); switch (type) { case "beef": rice = new BeefFriedRice(factory); break; } return rice; }}Copy the code

describe

  • Schema name: ABSTRACT FACTORY
  • Type: Object creation mode
  • Intent: Provide an interface for creating a series of related or interdependent objects without specifying their concrete classes.
  • Applicability:
    • When a system is to be configured by one of multiple product families.
    • When you want to emphasize the design of a series of related product objects for joint use.
  • Effect:
  • Advantages:
    • Concrete classes are separated, making it easy to switch concrete factories.
    • When multiple objects in a product family are designed to work together, it ensures that clients always use only objects in the same product family.
  • Disadvantages:
    • It is difficult to extend the abstract factory to produce new kinds of products, and adding new products requires modifying the code of the abstract factory, breaking the open and close principle.

The class diagram

Case class diagram

The abstract factory pattern provides interfaces for creating families of related or dependent objects without specifying explicit classes. In the above scenario, by using an abstract factory, the upper level modules are decoupled from the lower level modules so that the upper level modules do not have to relate to what the concrete classes are.

Abstract factory class diagram

  1. AbstractFactory: Provides an interface for creating products. It contains multiple product-creating methods called createProduct(), which can create multiple different products.
  2. ConcreteFactory: ConcreteFactory implements abstract methods in abstract factories to create concrete products.
  3. Abstract Products: Defines a specification for a Product and describes its main features and functions. The Abstract factory pattern has multiple abstract products.
  4. Concreteproducts: Interfaces that implement abstract product roles and are created by concrete factories in a many-to-one relationship.

In summary, the goal of any factory pattern is to decouple the ability to create objects, either through inheritance to subclasses (factory method) or through interfaces to create families of objects (abstract factories).