The factory mode of design mode is the strongest in history. It's hard to argue against it!

Design pattern is a high-level abstract summary of various codes written in your actual work. If you don't learn design pattern, the abstraction ability will certainly not be too strong. There are 23 common design patterns. Today we only talk about the simplest factory pattern.

Factory mode is a creation mode, which obtains new objects one by one through the factory. To put it bluntly, the factory is used to create new objects, so it is divided into creation type.

Simple factory mode

The simple factory model, just like its name, is as simple as its name, very simple. Let's look at a code first:

public class FoodFactory {
    public static Food makeFood(String name) {
        if ("kuaican".equals(name)) {
            Food kuaican = new KuaiCanFood();
            kuaican.setPrice(20.00);
            return kuaican;
        } 

        if ("hamburger".equals(name)) {
            Food hamburger = new HamburgerFood();
            hamburger.setPrice(22.00);
            hamburger.setMeat("beef");
            return hamburger;
        } 

        // ......

        return new RuntimeException("not food");
    }
}

It should be noted that KuaiCanFood and hamburger Food in the above inherit from Food.

In short, the simple factory pattern is usually like this. A factory class XxxFactory has a static method that returns different instance objects derived from the same parent class (or implementing the same interface) according to our different parameters.

We emphasize the principle of single responsibility. A class only provides one function. The function of FoodFactory is to produce all kinds of Food.

In various Java frameworks, the simple factory pattern is very common, such as JedisConnectionFactory.

Redis connection factory

Basically, the frameworks that need to create connections in Java use the factory pattern.

Factory mode

The simple factory model is very simple. In general, it can meet our needs. However, in some special scenarios, it can not meet our needs. Take redis as an example. Redis has stand-alone mode, master-slave mode, sentinel mode and Cluster mode. The connection of each mode is different, so we need to introduce multiple factories.

In this case, it is necessary to introduce multiple simple factory patterns. For example: JedisConnectionFactory, JredisConnectionFactory, letticconnectionfactory, SrpConnectionFactory, etc. The reason why we need to introduce the factory model is that we often need to use two or more factories.

Let's take Food as an example.

public interface FoodFactory {
    Food makeFood(String name);
}
public class ChineseFoodFactory implements FoodFactory {
    @Override
    public Food makeFood(String name) {
        if ("Package A".equals(name)) {
            Food kuaican = new KuaiCanFood();
            kuaican.setPrice(20.00);
            kuaican.setName("Fast Food");
            return kuaican;
        } 
        
        if ("Package B".equals(name)) {
            Food mifan = new MiFanFood();
            mifan.setPrice(18.00);
            mifan.setName("Wuchang rice ");
            return mifan;
        } 
        
        return null;
    }
}
public class AmericanFoodFactory implements FoodFactory {
    @Override
    public Food makeFood(String name) {
        if ("Package A".equals(name)) {
            Food hamburger = new HamburgerFood();
            hamburger.setPrice(22.00);
            hamburger.setName("hamburger");
            return hamburger;
        } 
        
        if ("Package B".equals(name)) {
            Food sandwich = new SandwichFood();
            sandwich.setPrice(25.00);
            sandwich.setName("Sandwich");
            return sandwich;
        } 
        
        return null;
    }
}

Among them, KuaiCanFood, mifan Food, hamburger Food and sandwich Food are all derived from Food.

Consumer call:

public class Consumer {
    public static void main(String[] args) {
        // Select a specific factory first
        FoodFactory factory = new ChineseFoodFactory();
        // Specific objects are generated by the selected factories, and different factories create different objects
        Food food = factory.makeFood("Package A");
    }
}

Although package A is made by calling makeFood("package A"), it is completely different from that produced by different factories.

In the first step, we need to select a suitable factory, and then the second step is basically the same as a simple factory.

The core is that we need to choose the factory we need in the first step. For example, we have the FileFactory interface, and the implementation classes are AliyunOssFactory and TencentCosFactory, which respectively write files to alicloud OSS and Tencent cloud COS. Obviously, in the first step, our clients or consumers need to decide whether to instantiate AliyunOssFactory or TencentCosFactory, which will determine all subsequent operations.

The factory model is very simple. I draw them all on a picture. I hope you can look at the picture and see:

Factory mode

It's not true now. You must use it in practice code, or you'll forget it soon!

Abstract factory pattern

With simple factory patterns and factory patterns, why are there Abstract Factory patterns?

This is when it comes to product families, it is necessary to introduce the abstract factory pattern. When there are multiple different types of products in a product family (such as the Redis connection factory I listed above), the problem of selecting different connection factories according to different architecture modes. Such scenarios are also very common in business development, but they may not be abstracted sometimes.

Redis connection factory

I won't say more about the RedisConnectionFactory example. I suggest you read the source code in spring data redis several times. Let me cite another classic example in life, that is, building a mobile phone. Let's not introduce the abstract factory pattern and see how to implement it.

Because the mobile phone is composed of many components, we abstract the processor CPU and the motherboard, and then the CPU is produced by CpuFactory, and the motherboard is produced by MainBoardFactory. Then, we combine the CPU with the motherboard, as shown in the following figure:

Abstract factory pattern

If you need a mobile phone product at this time, just call:

public class Phone {
    private Cpu cpu;
    private MainBoard mainBoard;
    public Phone(Cpu cpu, MainBoard mainBoard){
        this.cpu = cpu;
        this.mainBoard = mainBoard;
    }
    public static void main(String[] args) {
        // Get Huawei's processor
        CpuFactory KirinFactory = new HuaweiCpuFactory();
        Cpu cpu = KirinFactory.getCpu();
        // Get Huawei's motherboard
        MainBoardFactory mainBoardFactory = new HuaweiMainBoardFactory();
        MainBoard mainBoard = mainBoardFactory.getMainBoard();
        // Assemble mobile phone CPU and motherboard
        Phone huaweiMate = new Phone(cpu, mainBoard);
    }
}

Look at the processor CPU factory and motherboard factory separately. They are the factory mode we mentioned earlier. This method is also easy to expand, because if you want to add accessories to the mobile phone, you only need to add an XxxFactory and the corresponding implementation, without modifying the existing factory.

However, there is a problem with this method, that is, if Apple???? The home-made CPU and the motherboard made by Huawei are not compatible, so there can be no arbitrary combination. This is the concept of product family, which represents the collection of a series of accessories that make up a product.

When it comes to the problem of this product family, it needs to be supported by the abstract factory pattern. We no longer define CPU factories, mainboard factories, OS factories, display screen factories, etc. we directly define mobile phone factories. Each mobile phone factory is responsible for producing all equipment, which can ensure that there is no compatibility problem.

public interface PhoneFactory {
    Cpu getCpu();
    MainBoard getMainBord();
    Display getDisplay();
}
public class HuaweiPhoneFactory implements PhoneFactory {
    @Override
    public Cpu getCpu() {
        return new HuaweiCpu();
    }
    @Override
    public MainBoard getMainBord() {
        return new HuaweiMainBoard();
    }
    @Override
    public Display getDisplay() {
        return new BoeDisplay();
    }
}
public class XiaomiPhoneFactory implements PhoneFactory {
    @Override
    public Cpu getCpu() {
        return new HuaweiCpu();
    }
    @Override
    public MainBoard getMainBord() {
        return new XiaomiMainBoard();
    }
    @Override
    public Display getDisplay() {
        return new VisionoxDisplay();
    }
}

In this case, for production, it is no longer necessary to select CPU manufacturers and display manufacturers separately, but directly select a brand factory. The brand factory will be responsible for producing all things and ensure that they are compatible and available.

public class Test {
    public static void main(String[] args) {
        // The first step is to select a "big brand factory"
        PhoneFactory factory = new HuaweiPhoneFactory();
        // Design and manufacture CPU from this large factory
        Cpu cpu = factory.getCpu();
        // Mobile phone motherboards are produced from this large factory
        MainBoard board = factory.getMainBord();
        // We produce mobile phone display screens from this big factory
        Display boeDisplay = factory.getDisplay();
        // Production of a Huawei meter 40 mobile phone
        Phone huaweiMete40 = new Phone(cpu, board, boeDisplay);
    }
}

The code and case of such an abstract factory will be finished. If there is anything else I don't understand, I'll explain to you the case of our current production project next time!

Finally, to sum up, according to different requirements and functions, you can choose the corresponding simple factory, ordinary factory and abstract factory. The abstract factory looks more abstract, and the problems it exposes are also obvious. For example, if we want to add an NFC module, we need to modify all factories and add the method of manufacturing displays to all factories. This is a bit against the design principle of closing to modifications and opening to extensions. But don't completely copy the design principles. After all, sometimes you need to break the principles, don't you? For example, some anti paradigm design in e-commerce system.

Posted on Tue, 07 Dec 2021 01:46:08 -0500 by sheffrem