Java Design Mode-Factory Mode

1. Simple factories

Definition

Simple Factory is not actually one of the 23 GOF design modes. It is a weakening (or a special case of) the factory method mode. Because it is simple, it is called Simple Factory Mode, also known as static factory mode.Although it's not a "standard" design pattern (more like a programming habit), there are many cases where this approach is used in real projects.

There is no strict definition for the simple factory mode, let's use the following description for a moment:

Provides the ability to create an instance of an object without concern for its implementation.The type of instance created can be an interface, an abstract class, or a concrete class

key point

  • Specific factory class
  • Factory method for creating products

    • Static method (origin of static factory name)
    • There is usually a Type parameter (and one that allows you to provide multiple static factory methods and differentiate the products to be created by different method names)
    • Create a product with if or switch based on the parameters and return

Realization

Abstract product class (interface or abstract class)

public interface Product {
    void doSomething();
    void doAnything();
}

Specific product classes

public class ConcreteProductA implements Product {
    @Override
    public void doSomething() {
        System.out.println("ConcreteProductA doSomething");

    }

    @Override
    public void doAnything() {
        System.out.println("ConcreteProductA doAnything");
    }
}
public class ConcreteProductB implements Product {
    @Override
    public void doSomething() {
        System.out.println("ConcreteProductB doSomething");

    }

    @Override
    public void doAnything() {
        System.out.println("ConcreteProductB doAnything");
    }
}

Factory Class

public class Creator {

    public static Product createProduct(String type) {
        Product product = null;
        switch (type) {
            case "A":
                product = new ConcreteProductA();
                break;
            case "B":
                product = new ConcreteProductB();
                break;
        }
        return product;
    }
}

Client Code

public class Client {

    public static void main(String[] args) {
        Product productA = Creator.createProduct("A");
        productA.doSomething();
        productA.doAnything();
      
        Product productB = Creator.createProduct("B");
        productB.doSomething();
        productB.doAnything();
    }

}

Advantage

  • simple
  • decoupling

    • Clients do not need to depend on specific product classes, they only depend on factory classes, and they can get different objects by passing in different parameters.
    • Factory methods can return different subclasses of the same type based on user conditions.
    • Additional details of creating objects can be added to the factory method and blocked from clients.

shortcoming

It is very difficult to expand the factory class. For each additional product, it is necessary to add the corresponding branch in the factory. It is open to expansion and also open to modifications, which does not conform to the principle of opening and closing.If there are many products, then the factory method is particularly "bloated", reduces readability and is not easy to maintain.

Use scenarios

  • A replacement for new, where objects need to be created with new, consider simple factories;
  • There are fewer types of products, and you can basically anticipate situations where you don't need too many extensions (product requirements are almost certain, such as calculators, where there are probably so many known types of operations)

2. Plant Methods

Definition

Define an interface for creating an object,but let subclasses decide which class toinstantiate.Factory Method lets a class defer instantiation to subclasses.

Define an interface for creating objects so that subclasses decide which class to instantiate.Factory methods delay the instantiation of a class to its subclasses.

Realization

Abstract product class

public interface Product {
    void doSomething();
    void doAnything();
}

Specific product classes

public class ConcreteProductA implements Product {
    @Override
    public void doSomething() {
        System.out.println("ConcreteProductA doSomething");

    }

    @Override
    public void doAnything() {
        System.out.println("ConcreteProductA doAnything");
    }
}
public class ConcreteProductB implements Product {
    @Override
    public void doSomething() {
        System.out.println("ConcreteProductB doSomething");

    }

    @Override
    public void doAnything() {
        System.out.println("ConcreteProductB doAnything");
    }
}

Abstract factory class

public interface Creator {
    Product createProduct();
}

Specific factory class

public class ConcreteCreatorA implements Creator {
    @Override
    public Product createProduct() {
        return new ConcreteProductA();
    }
}
public class ConcreteCreatorB implements Creator {
    @Override
    public Product createProduct() {
        return new ConcreteProductB();
    }
}

Client Code

public static void main(String[] args) {
        Creator creatorA = new ConcreteCreatorA();
        Product productA = creatorA.createProduct();
        productA.doSomething();
        productA.doAnything();

        Creator creatorB = new ConcreteCreatorB();
        Product productB = creatorB.createProduct();
        productB.doSomething();
        productB.doAnything();
    }

Advantage

  • Good encapsulation, clear code structure

    An object creation is conditionally constrained. For example, a caller needs a specific product object, as long as he knows the class name (or constraint string) of the product, he or she does not need to know the arduous process of creating objects to reduce the coupling between modules.

  • The extensibility of the factory method pattern is excellent

    With the addition of product classes, embracing change can be accomplished by modifying a specific factory class or extending a factory class appropriately.

  • The factory method pattern is a typical decoupling framework
  • High-level module values need to know the abstract class of the product, other implementation classes don't need to care about, comply with Dimiter's rule, I don't need to communicate; also conform to the principle of dependent inversion, relying only on the abstract of the product class; of course, also conform to the principle of Riesian replacement, using product subclasses to replace the product parent.

shortcoming

For each additional product class, you need to add a corresponding factory class, which adds an additional amount of development.

extend

Use the reflection mechanism to solve the problem of adding a corresponding factory class for each additional product class

Abstract factory class

public interface Creator {
    <T extends Product> T createProduct(Class<T> clazz);
}

Specific factory class

public class ConcreteCreator implements Creator {
    @Override
    public <T extends Product> T createProduct(Class<T> clazz) {
        Product product= null;
        try {
            product = (Product) Class.forName(clazz.getName()).newInstance();
        } catch (InstantiationException | IllegalAccessException | ClassNotFoundException e) {
            e.printStackTrace();
        }
        return (T) product;
    }
}

Client Code

public class Client {
    public static void main(String[] args) {
        Creator creator = new ConcreteCreator();

        Product productA = creator.createProduct(ConcreteProductA.class);
        productA.doSomething();
        productA.doAnything();

        Product productB = creator.createProduct(ConcreteProductB.class);
        productB.doSomething();
        productB.doAnything();
    }
}

Factory Method VS Simple Factory

The factory method pattern is a further abstraction and decoupling of simple factories.Compared to simple factories:

  • The factory method pattern has one more abstract factory class
  • Each product corresponds to a specific factory class
  • The factory method mode transfers the internal logic judgment of a simple factory to the client code.The creation code for each instance object is not coupled in the same factory class.
  • The factory method mode is easier to expand, overcomes the shortcomings of simple factories that violate the open-close principle, and maintains the advantages of creating encapsulated objects.

3. Abstract Factory

Definition

Provide an interface for creating families of related or dependent objects without specifyingtheir concrete classes.

Provides an interface for creating a set of related or interdependent objects without specifying their specific classes.

Realization

Abstract product class

Product A Family

public interface ProductA {
    void doSomething();
    void doAnything();
}

Product B Family

public interface ProductB {
    void doSomething();
    void doAnything();
}

Specific product classes

Product A family, product grade 1

public class ConcreteProductA1 implements ProductA {
    @Override
    public void doSomething() {
        System.out.println("ConcreteProductA1 doSomething");
    }

    @Override
    public void doAnything() {
        System.out.println("ConcreteProductA1 doAnything");
    }
}

Product A family, product grade 2

public class ConcreteProductA2 implements ProductA {
    @Override
    public void doSomething() {
        System.out.println("ConcreteProductA2 doSomething");
    }

    @Override
    public void doAnything() {
        System.out.println("ConcreteProductA2 doAnything");
    }
}

Product B family, product grade 2

public class ConcreteProductB1 implements ProductB {
    @Override
    public void doSomething() {
        System.out.println("ConcreteProductB1 doSomething");
    }

    @Override
    public void doAnything() {
        System.out.println("ConcreteProductB1 doAnything");
    }
}

Product B family, product grade 2

public class ConcreteProductB2 implements ProductB {
    @Override
    public void doSomething() {
        System.out.println("ConcreteProductB2 doSomething");
    }

    @Override
    public void doAnything() {
        System.out.println("ConcreteProductB2 doAnything");
    }
}

Abstract factory class

public interface Creator {
    /**
     * Create A Product Family
     * @return
     */
    ProductA createProductA();

    /**
     * Create B Product Family
     * @return
     */
    ProductB createProductB();

    // ...
    // There are N product families, there should be N creation methods in the abstract factory class
}

There are N product families, there should be N creation methods in the abstract factory class

Specific factory class

public class ConcreteCreator1 implements Creator {
    @Override
    public ProductA createProductA() {
        return new ConcreteProductA1();
    }

    @Override
    public ProductB createProductB() {
        return new ConcreteProductB1();
    }
}
public class ConcreteCreator2 implements Creator {
    @Override
    public ProductA createProductA() {
        return new ConcreteProductA2();
    }

    @Override
    public ProductB createProductB() {
        return new ConcreteProductB2();
    }
}

With M product levels, there should be M specific factory implementations

Client Code

public class Client {
    public static void main(String[] args) {
        Creator creator1 = new ConcreteCreator1();

        ProductA productA1 = creator1.createProductA();
        productA1.doSomething();
        productA1.doAnything();

        ProductB productB1 = creator1.createProductB();
        productB1.doSomething();
        productB1.doAnything();

        Creator creator2 = new ConcreteCreator2();

        ProductA productA2 = creator2.createProductA();
        productA2.doSomething();
        productA2.doAnything();

        ProductB productB2 = creator2.createProductB();
        productB2.doSomething();
        productB2.doAnything();
    }
}

Advantage

  • Encapsulability, high-level modules don't need to care about the implementation class of each product, how objects are created, as long as you know who the factory class is, you can create an object you need
  • 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, and it is easy to exchange product families.
  • Constraints within the product family can be defined and are transparent to high-level modules

shortcoming

The biggest disadvantage of the abstract factory model is that it is very difficult to extend the product family. For example, if you want to add a product C, that is, to increase the product family from two to three, to add a method, createProductC(), to the abstract factory class Creator, then modify each implementation class, which violates the open-close principle.

Note that it is difficult to expand the product family, not the product hierarchy. If you add a new product hierarchy, you only need to add an implementation of a specific factory class to complete the expansion.

Abstract Factory VS Factory Method

The abstract factory mode is an upgraded version of the factory method mode. When there are multiple business varieties and business classifications, generating the desired objects through the abstract factory mode is a very good solution.

Factory method mode produces one product and abstract factory mode produces multiple products (a series of products); in programming, it is usually represented as an interface or abstract class, that is, all products provided by factory method mode derive from the same interface or abstract class, while products provided by abstract factory mode derive from different interfaces or abstract classes.

4. Summary

Three patterns, simple factory, factory method, and abstract factory, are progressively abstract, the latter being applied to more general scenarios, while the former is a special case of the latter.However, their goals are the same. They all have the flexibility to create the objects needed and create details for hiding objects from the client. They vary in scalability and amount of development. You can choose the appropriate mode to replace the process of creating objects in the new way according to the actual situation:

  • Simple factories are suitable for scenarios where there are fewer product types and not too many extensions
  • As a further abstraction and complement to simple factories, the factory method pattern is more applicable in scenarios with many extended requirements
  • If a product family has the same constraints (when there are multiple business varieties, business classifications, i.e., concepts with a product family-product hierarchy), the abstract factory model can be used

    For example, a text editor and a picture processor are both software entities, but the text editor under *nix and the text editor under Windows have the same functions and interfaces, but the code implementation is different and the picture processor has the same situation.That is, there is a common constraint: the operating system type.So we can use abstract factory mode to generate editors and picture processors for different operating systems.

Source address: https://gitee.com/tianranll/java-design-patterns.git

References: Zen in Design Mode, Dahua Design Mode

Keywords: Java Programming Windows git

Added by jplock on Fri, 14 Jun 2019 19:03:51 +0300