This is the 11th day of my participation in the August More Text Challenge.

Design Pattern #2 (Factory Pattern)



Brief description: Provides the best way to create objects.

In factory mode, we create objects without exposing the creation logic to the client, and by using a common interface to point to the newly created objects.

Interface oriented (abstract) programming? Do you smell the inside? The dependency inversion principle, Demeter’s rule and interface isolation principle are among the seven design principles.

Of course, more than one principle is used. A common design pattern is a collection of multiple design principles.

Simple Factory model

Description: Create a product interface. When you need a product, use the factory to create it.

Example:

public class negtive {
/*=============== server ======================*/
    interface Food{
        void eat(a);
    }

    static class Noodles implements Food{
        @Override
        public void eat(a) {
            System.out.println("Eat noodles..."); }}/*================= client ===================*/
    public static void main(String[] args) {
        Food food01 = newNoodles(); food01.eat(); }}Copy the code

The UML class diagram is as follows:

At this time, the product to change the demand, “brother, you put down the knife first. Now I’ll change my name to Noodles and show you how to make Spaghetti.”

At this point, since your original design is a counter example, you need to be able to modify the server source and then the client source. In the future, when you change your name, you have to take the knife out and put it on the table to show the product.

This design is too fragile because the server source code and the client source code are coupled, and changes can affect everything.

Is:

public class postive {

    /*=============== server ======================*/
    interface Food{
        void eat(a);
    }

    static class Spaghetti implements Food {
        @Override
        public void eat(a) {
            System.out.println("Eat western noodles..."); }}static class FoodFactory {
        public Food getFood(int num){
            Food food =null;
            switch (num){
                case 1 :
                    food = new Spaghetti();
            }
            returnfood; }}/*================= client ===================*/
    public static void main(String[] args) {
        FoodFactory foodFactory = new FoodFactory();
        Food food01 = foodFactory.getFood(1); food01.eat(); }}Copy the code

The UML class diagram is as follows:

With an example like this, you leave all the object creation code to the server, and ** decouples the server code from the client code. ** The product will talk to you later, can you put away the knife temporarily?

The benefits of this are not limited to the server-side developers; when the server-side code changes, the client doesn’t know about it and doesn’t need to know about it.

Such a design pattern is not perfect, and no design pattern is perfect. It’s just making trade-offs based on business logic.

Disadvantages of the simple factory pattern:

  • Customers must remember the mapping between constants and specific products in the factory.
  • Once the product variety size increases to a certain point, the factory class will become very bloated.
  • The most fatal flaw, when adding products, is to modify the factory class. Violate the open and close principle.

Factory method pattern

Description: In order to expand, do not violate the open closed principle.

This is an improvement based on the simple factory pattern.

Is:

public class postive {
    /*=============== server ======================*/
    / / -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- - -- -- -- -- -- -- -- -- -- -- -- -- -- --
    interface Food{
        void eat(a);
    }

    static class Spaghetti implements Food {
        @Override
        public void eat(a) {
            System.out.println("Eat western noodles..."); }}// Add new products
    static class Rice implements Food {
        @Override
        public void eat(a) {
            System.out.println("Eat rice..."); }}/ / -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- - the factory -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
     interface FoodFactory {
         Food getFood(a);
    }

    static class SpaghettiFactory implements FoodFactory{

        @Override
        public Food getFood(a) {
            return newSpaghetti(); }}// Add product factory
    static class RiceFactory implements FoodFactory{

        @Override
        public Food getFood(a) {
            return newRice(); }}/*================= client ===================*/
    public static void main(String[] args) {
         FoodFactory foodFactory = newSpaghettiFactory(); Food food01 = foodFactory.getFood(); food01.eat(); }}Copy the code

The UML class diagram is as follows:

Aiming at the defect that the simple factory violates the open and close principle, the factory method mode is optimized. You can see that when you add products, you no longer need to modify the factory class, but to add the corresponding product class and factory class. This is in accordance with the open closed principle.

There will be clever little question mark has a lot of friends:

  1. If the source code author changes the name of the relevant factory class, then the client code calling the factory class needs to be changed. How about a simple factory?

Interface classes are generally not allowed to be modified (not required). The factory class author has the responsibility to ensure that the factory class name is stable. In other words, the factory class is more stable than the product class.

  1. Now that we make our own extension laterRiceClass, why not instantiate it directly, use it directly. We are the authors. Why can’t we just use it?

As an extension, sometimes a product class does not stand alone, but together with other classes forms a service framework.

Add some classes below:

	/*=============== server ======================*/	  
	/ / -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- product quality inspection process -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --,

    static class QualityInspection {

        public void checking(FoodFactory foodFactory){
            System.out.println("I'm a human flesh inspector... Ready to eat - -"); Food food = foodFactory.getFood(); food.eat(); }}/*================= client ===================*/
    public static void main(String[] args) {
        FoodFactory foodFactory01 = new  SpaghettiFactory();
        FoodFactory foodFactory02 = new  RiceFactory();

        QualityInspection inspection = new QualityInspection();
        inspection.checking(foodFactory02);
        inspection.checking(foodFactory01);
Copy the code

The UML class diagram is as follows:

At this point, if Rice doesn’t have his factory class and can’t even participate in quality inspection, how can he sell it?

So factory classes are written not just to instantiate some product classes, but to allow supporting services to invoke the factory to create product instances through the factory interface.

Why doesn’t the Checking method of QualityInspection directly invoke the Food interface before instantiating the product?

At this point, back to the simple factory model, the product class is different from the factory class, it is fickle, it will change with the change of demand, at this point, the various methods that rely directly on the product class will need to be modified, violating the open and closed principle. This is a dead end, kid. Ha, ha, ha.

Of course, the factory approach pattern is also flawed:

  • When the business needs more types, currently only food, when drinks, daily necessities and other categories, we have to create new factories to achieve, resulting in bloated code duplication.

Abstract Factory pattern

The abstract factory pattern is modified to address the shortcomings of the factory method pattern, where a factory is responsible for creating objects for a product cluster.

Product cluster: refers to multiple products that have internal or logical relationships.

Brief description: In the abstract factory pattern, an interface is a factory responsible for creating a related object, without explicitly specifying their classes. Each generated factory can provide objects according to the factory pattern.

The Abstract Factory Pattern creates other factories around a gigafactory. The gigafactory is also known as the factory of other factories. This type of design pattern is the creation pattern, which provides the best way to create objects.

Is:

public class postive {
    /*=============== server ======================*/
    
    / / -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- - -- -- -- -- -- -- -- -- -- -- -- -- -- --
    / * -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- screw -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- - * /
    interface Screw{
        void createScrew(a);
    }

    static class Screw_06 implements Screw {
        @Override
        public void createScrew(a) {
            System.out.println("Create Screw_06 666666..."); }}static class Screw_08 implements Screw {
        @Override
        public void createScrew(a) {
            System.out.println("Create Screw_08 8888888..."); }}/ * -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- nut -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- - * /
    interface Nut{
        void createNut(a);
    }

    static class Nut_06 implements Nut {
        @Override
        public void createNut(a) {
            System.out.println("Create Nut_06 666666..."); }}static class Nut_08 implements Nut {
        @Override
        public void createNut(a) {
            System.out.println("Create Nut_08 8888888..."); }}/ / -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- - the factory -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
    interface ComponentsFactory {
        Screw getScrew(a);
        Nut getNut(a);
    }
    /*---------------- No. 6 factory ---------------------*/
    static class Factory_666 implements ComponentsFactory {

        @Override
        public Screw getScrew(a) {
            return new Screw_06();
        }

        @Override
        public Nut getNut(a) {
            return newNut_06(); }}/*---------------- No. 8 factory ---------------------*/
    static class Factory_888 implements ComponentsFactory {

        @Override
        public Screw getScrew(a) {
            return new Screw_08();
        }

        @Override
        public Nut getNut(a) {
            return newNut_08(); }}/ / -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- product quality inspection process -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --,
    static class QualityInspection {

        public void checking(ComponentsFactory Factory){
            System.out.println("I'm a human flesh inspector... Parts waiting for output -_-");
            Screw screw = Factory.getScrew();
            Nut nut = Factory.getNut();
            screw.createScrew();
            nut.createNut();
            System.out.println("Start quality inspection.......");
            System.out.println(""); }}/*================= client ===================*/
    public static void main(String[] args) {
        ComponentsFactory Factory01 = new   Factory_666();
        ComponentsFactory Factory02 = new   Factory_888();

        QualityInspection inspection = newQualityInspection(); inspection.checking(Factory01); inspection.checking(Factory02); }}Copy the code

The UML class diagram is as follows:

It can be seen that if an extension of n-size screw or nut is needed, it only needs to add a product class that realizes the interface of N-size screw or nut, and use a newly added N-size factory to create it.

As you can see, the abstract factory retains the advantages of the simple factory pattern and the factory method pattern:

  • The server code and client code are poorly coupled. (Simple Factory Mode)
  • All these actions are new, not modified, in line with the open and closed principle.

A unique advantage has been added:

  • Abstract factories effectively reduce the number of factories, where a factory produces products from the same product cluster.

This next product to change the demand, is it possible to smile and chat with him?

Again, an abstract factory is responsible for creating objects of the same product cluster. The product cluster refers to a number of internally related or logically related products. That is, factory 6 only produces parts of Factory 6, not parts of factory 8. Products from different product clusters cannot be mixed into one plant for production.

Defect: When adding clusters (increasing production of nuts 6 and 8), it is necessary to modify the source code of previous factories (factories 6 and 8).


The summary is:

  • When the product cluster is relatively fixed, consider using an abstract factory.
  • Abstract factories are not recommended when products change frequently.