C# design pattern — simple factory pattern, factory pattern, abstract factory pattern

Time:2021-12-29

1. Foreword

In the last article, we wrote the design pattern principles, which can help us write high-quality code when developing programs (pull the hair without touching the whole body). In this series, we still take notes to review various design patterns. Let’s take a look at simple factory patterns, factory patterns and abstract factory patterns.

2. Simple factory mode

In fact, we can understand that the simple factory pattern is a class specifically responsible for production objects, which is used to create instances of specific products. When we usually create an object, it is usually new. At this time, this class depends on this object. In other words, the coupling is too high. When the requirements change, we have to modify the source code of this kind. At this time, it is necessary to use the idea of object-oriented (OO) to deal with this problem. Encapsulate the class with great changes, and the implementation will not touch it. Let’s take a look at chestnuts, and analyze the role of simple factory mode in producing and manufacturing different cars.

/// 
///Car abstract class
/// 
public abstract class Car
{
    /// 
    ///Manufacturing vehicle -- abstract method
    /// 
    public abstract void Make();
    /// 
    ///Selling cars -- abstract method
    /// 
    public abstract void Sale();
}

/// 
///Audi
/// 
public class ADCar : Car
{
    public override void Make()
    {
        Console. Writeline ("built an Audi");
    }

    public override void Sale()
    {
        Console. Writeline ("sold an Audi");
    }
}
/// 
///Mercedes Benz
/// 
public class BCCar : Car
{
    public override void Make()
    {
        Console. Writeline ("built a Mercedes Benz");
    }

    public override void Sale()
    {
        Console. Writeline ("sold a Mercedes Benz");
    }
}

Look at the call of the client

Car c = new ADCar();
c.Make();
c.Sale();
Console.WriteLine("\n");
Car b = new BCCar();
b.Make();
b.Sale();

We can see that we all create an instance through a new adcar. If we want a Mercedes Benz, we need a new one. I want n, it’s not a fryer. So here we create a simple factory class for cars. Let this factory class create a car instance. The switch here is c#’s grammar sugar. Does it feel a little fragrant.

/// 
///Factory type of vehicle
/// 
public  class CarFactory
{
    public static Car OpCar(string carName)
    {
        Car? car = null;
        var ret = carName switch
        {
            "AD" => car=new ADCar(),
            "BC" => car=new BCCar(),
            _ => car=new ADCar()
        };
        return ret;
    }

}

//Client call
Car cc = CarFactory.OpCar("AD");
cc.Make();
cc.Sale();

Car cc1 = CarFactory.OpCar("BC");
cc1.Make();
cc1.Sale();

At this time, it’s OK. It solves the problem that the client is too dependent on specific objects. Don’t worry. If I have another BMW, I’ll add a bmcar that inherits the car, and add another judgment in the opcar of carfactory. According to the opening and closing principle, adding classes has no impact, but modifying the opcar code in carfactory does not comply with the opening and closing principle. The following factory model specifically solves this problem.

3. Factory mode

In the simple factory mode, the system is difficult to expand and violates the opening and closing principle, which makes the implementation logic of the simple factory too complex. The factory pattern is to place the instance of the concrete creation class in the sub factory class,The factory class is no longer responsible for the creation of all products. The factory class only provides creation instances。 Or look at the chestnuts above. Let’s add an abstract factory class for different brands to inherit

/// 
///Car factory
/// 
public abstract class CarFactory1
{
    /// 
    ///Abstract method
    /// 
    public abstract Car OpCar();
}
/// 
///Audi factory
/// 
public class ADCarFactory1 : CarFactory1
{
    public override Car OpCar()
    {
        return new ADCar();// Instantiate products in specific factories
    }
}
/// 
///Mercedes Benz factory
/// 
public class BCCarFactory1 : CarFactory1
{
    public override Car OpCar()
    {
        return new BCCar();// Instantiate products in specific factories
    }
}


//Client call
CarFactory1 cf = new ADCarFactory1();
Car car = cf.OpCar();
car.Make();
car.Sale();

CarFactory1 cf2 = new BCCarFactory1();
Car car2 = cf2.OpCar();
car2.Make();
car2.Sale();

The effect is the same as above. Is it possible to add a BMW here without modifying the code in the factory? Just create a bmcarfactory1 and bmcar.When we want to obtain a product, we will obtain a specific factory to instance it。 Does it not only solve the shortcomings of simple factories, but also comply with the opening and closing principle. The problem also comes. If I don’t just want to sell cars, I have to sell planes and rockets. It’s impossible to create countless factories. Take a look at the abstract factory pattern.

4. Abstract factory pattern

The factory model has a single function, only for one brand, and can not solve a series of problems. It sells rockets, aircraft and other different brands. If we are in the design process, it is obvious that the factory model can no longer meet our needs. Abstract factory pattern can solve this problem well. Here we still add an abstract class, which provides colleagues who manufacture and sell cars, as well as aircraft. The realization method is just to realize the products of your own brand.

/// 
///Product abstract class
/// 
public abstract class PcFactory
{
    /// 
    ///Car
    /// 
    /// 
    public abstract Car OpCar();
    /// 
    ///Aircraft
    /// 
    /// 
    public abstract Plan OpPlan();
}
/// 
///Audi PC factory
/// 
public class ADPcFactory : PcFactory
{
    public override Car OpCar()
    {
        return new ADCar();
    }

    public override Plan OpPlan()
    {
        return new ADPlan();
    }
}
/// 
///Benz PC factory
/// 
public class BCPcFactory : PcFactory
{
    public override Car OpCar()
    {
        return new BCCar();
    }

    public override Plan OpPlan()
    {
        return new BCPlan();
    }
}

//Client call
PcFactory pf = new ADPcFactory();
Car adc = pf.OpCar();
Plan adc2 = pf.OpPlan();
adc.Make();
adc.Sale();

adc2.Make();
adc2.Sale();

PcFactory pf2 = new BCPcFactory();
Car abc = pf2.OpCar();
Plan abc2 = pf2.OpPlan();
abc.Make();
abc.Sale();

abc2.Make();
abc2.Sale();

We can see that the difference between abstract factory and factory is that it can produce a variety of products (cars and aircraft), and the factory can only be a single product (cars).Abstract classes only focus on creating multiple products and do not care about the specific implementation。 It is impossible to realize the product factory. In this way, the client is also decoupled from the specific product.

5. Summary

Simple factory mode

Advantages: reduce the coupling between the scale segment and specific products, realize new, let the factory class complete it, and improve the reuse rate of the code.

Disadvantages: it violates the opening and closing principle, the system is difficult to expand, and the factory class centralizes all business logic. Once something goes wrong, the whole system will be involved.

Factory mode

Advantages: in line with the opening and closing principle, the new function area will not modify the previous code.

Disadvantages: the product has a single function. The function of writing the car can only get the car, not the operation of aircraft and rockets.

Abstract factory pattern

Advantages: reducing system coupling is conducive to maintenance and expansion, and conforms to the opening and closing principle for plus series products;

Disadvantages: the addition of functions does not comply with the opening and closing principle. See if it conflicts with advantages. Let’s put it this way. Now I want to add a BMW class. I don’t need to modify the business logic. Just add a bmcarfactory1 and bmcar. These are a series of questions. If I want to add a destruction method (production and sales have been defined before), do I have to add an abstract method in the abstract classes car and plan? All inheritance should implement it. Therefore, it is troublesome not to consider the subsequent changes one by one at the beginning of program design.

A system is required not to be dependent on the specific implementation by all clients, which is the premise of the application of all factory modes, which requires specific analysis of specific problems. It’s impossible to say that I want to print a Holl word and engage in design patterns. It’s not necessary to shoot mosquitoes. There are good and bad modes. That’s what relativity says. When you get some, you are bound to lose some. Happiness should be accompanied by sadness. Will it be sunny after rain. After adding design patterns, the amount of code must go up, which will not only bring us convenience, but also increase the risk. Before, I didn’t understand why I had to create so many projects and folders. Now I think about it.

PS: time goes by like water, years go by like a song. It’s a kind of mind to bear grievances, and it’s a kind of mind to accept misunderstandings. It’s not terrible to lose anything in this world. The only terrible thing is to lose your heart and courage. As long as you struggle tenaciously, as long as your eyes look to the future, life will always belong to you, and the glory of life will always belong to you.

Recommended Today

MySQL related

Indexes Bottom structure Disadvantages of hash table index: Using hash storage requires adding all files to memory, which consumes more memory space If all queries are equivalent queries, the hash is indeed fast, but in the actual scene, more data is found, and not all queries are equivalent queries, so the hash table is not […]