Learning notes of design pattern: Abstract Factory Pattern

This note is excerpted from: https://www.cnblogs.com/PatrickLiu/p/7596897.html Record the learning process for future reference.

Next Learning notes of design mode: simple factory mode (prelude to factory method mode) Through the understanding of the simple factory model, its disadvantage is that we constantly modify the factory as the demand changes

In the last article, we talked about the factory method pattern, which is to solve the problem faced by the simple factory pattern: if we add new products, the factory method will modify its own code, and the more products we add, the more

More, the more complex the logic is. At the same time, such modification does not conform to the principle of open and closed OCP -- open to added code and closed to modified code. In order to solve the problem of simple factory, we introduced the factory method mode,

Through the classification of chemical plants, the division of factory responsibility is solved, so that products and corresponding factories correspond one by one, which conforms to OCP.

If we want to design a house, of course, we know that the house is composed of roof, floor, window, door, etc., first design a house with classical style, then create a house with modern style, and then create a house with modern style

A European style house, so many houses, what should we do? The abstract factory pattern we are going to talk about today can well solve multiple sets of changing problems.

II. Introduction to abstract factory model

Abstract Factory Pattern: English name -- Abstract Factory Pattern; classification -- creation type.

2.1. Motivation

In the software system, it is often faced with the creation of "a series of interdependent objects". At the same time, due to the change of requirements, there are often more series of objects. How to deal with this change? How

Bypassing the traditional object creation method (new), providing a "encapsulation mechanism" to avoid the tight coupling between the client program and this "multi series of concrete object creation work"?

2.2 intention

Provides an interface to create a series of related or interdependent objects without specifying their specific classes. ——Design mode GoF

2.3 Structure

This diagram is a UML diagram of abstract factory, which combines the intention, motivation and diagram of abstract factory to understand the pattern. Today, we take building a house as an example to illustrate the implementation mechanism of abstract factory.

2.4 composition of mode

As can be seen from the above figure, the structure diagram of the abstract factory pattern has the following roles:

1) abstract product: define abstract interface objects for each product that depends on each other in the abstract factory. In other words, if there are several products, it is necessary to declare several abstract roles,

Each abstract product role matches a specific product.

2) concrete product: concrete product class implements abstract product class, which is the type of implementation for a specific product.

3) Abstract Factory: defines the interface operations for creating a set of interdependent product objects, and each operation corresponds to each product one by one.

4) concrete factory: to implement all abstract interface operations in an abstract class, you can create a series of specific products, which are subclasses of the "abstract product class role".

2.5 concrete code implementation of abstract factory

As we grow older, we also reach the age of marriage. The first problem of marriage is the problem of the house. Suppose I have a rich dad (ER, dreaming )My brothers hope to have

A European style house, coupled with rural scenery, is leisurely. And I'm different. I want a modern house. Because the house consists of roof, floor, window and door (other groups

The roof, floor, windows and doors of each house are a system.

Let's take a look at how to use the abstract factory model to build different houses:

    class Program
    {
        /// <summary>
        /// Roof abstract class. The roof of a subclass must inherit this class.
        /// </summary>
        public abstract class Roof
        {
            /// <summary>
            /// Building roof
            /// </summary>
            public abstract void Create();
        }

        /// <summary>
        /// Floor abstract class. The floor of a subclass must inherit this class.
        /// </summary>
        public abstract class Floor
        {
            /// <summary>
            /// Create floor
            /// </summary>
            public abstract void Create();
        }

        /// <summary>
        /// Window abstract class, the window of subclass must inherit this class.
        /// </summary>
        public abstract class Window
        {
            /// <summary>
            /// Create windows
            /// </summary>
            public abstract void Create();
        }

        /// <summary>
        /// Door abstract class, the door of a subclass must inherit this class.
        /// </summary>
        public abstract class Door
        {
            /// <summary>
            /// Building doors
            /// </summary>
            public abstract void Create();
        }

        /// <summary>
        /// European roof
        /// </summary>
        public class EuropeanRoof : Roof
        {
            public override void Create()
            {
                Console.WriteLine("Creating a European roof");
            }
        }

        /// <summary>
        /// European flooring
        /// </summary>
        public class EuropeanFloor : Floor
        {
            public override void Create()
            {
                Console.WriteLine("Create European flooring");
            }
        }

        /// <summary>
        ///European windows
        /// </summary>
        public class EuropeanWindow : Window
        {
            public override void Create()
            {
                Console.WriteLine("Creating European windows");
            }
        }

        /// <summary>
        /// European doors
        /// </summary>
        public class EuropeanDoor : Door
        {
            public override void Create()
            {
                Console.WriteLine("Creating European style doors");
            }
        }

        /// <summary>
        /// Modern roof
        /// </summary>
        public class ModernizationRoof : Roof
        {
            public override void Create()
            {
                Console.WriteLine("Creating a modern roof");
            }
        }

        /// <summary>
        /// Modern flooring
        /// </summary>
        public class ModernizationFloor : Floor
        {
            public override void Create()
            {
                Console.WriteLine("Create modern flooring");
            }
        }

        /// <summary>
        /// Modern windows
        /// </summary>
        public class ModernizationWindow : Window
        {
            public override void Create()
            {
                Console.WriteLine("Creating modern windows");
            }
        }

        /// <summary>
        /// Modern doors
        /// </summary>
        public class ModernizationDoor : Door
        {
            public override void Create()
            {
                Console.WriteLine("Creating modern doors");
            }
        }

        /// <summary>
        /// Abstract factory class, which provides the interface to create different types of houses.
        /// </summary>
        public abstract class AbstractFactory
        {
            //The abstract factory provides the interface to create a series of products. The interface to create roofs, floors, windows and doors is shown here.
            public abstract Roof CreateRoof();
            public abstract Floor CreateFloor();
            public abstract Window CreateWindow();
            public abstract Door CreateDoor();
        }

        /// <summary>
        /// European style house factory, responsible for creating European style house.
        /// </summary>
        public class EuropeanFactory : AbstractFactory
        {
            //Making European roof
            public override Roof CreateRoof()
            {
                return new EuropeanRoof();
            }

            //Making European floor
            public override Floor CreateFloor()
            {
                return new EuropeanFloor();
            }

            //Making European windows
            public override Window CreateWindow()
            {
                return new EuropeanWindow();
            }

            //Making European doors
            public override Door CreateDoor()
            {
                return new EuropeanDoor();
            }
        }

        /// <summary>
        /// Now style house factory, responsible for creating modern style house.
        /// </summary>
        public class ModernizationFactory : AbstractFactory
        {
            //Making modern roofs
            public override Roof CreateRoof()
            {
                return new ModernizationRoof();
            }

            //Making modern flooring
            public override Floor CreateFloor()
            {
                return new ModernizationFloor();
            }

            //Making modern windows
            public override Window CreateWindow()
            {
                return new ModernizationWindow();
            }

            //Making modern doors
            public override Door CreateDoor()
            {
                return new ModernizationDoor();
            }
        }

        static void Main(string[] args)
        {
            #region Abstract factory pattern
            //European style house
            AbstractFactory europeanFactory = new EuropeanFactory();
            europeanFactory.CreateRoof().Create();
            europeanFactory.CreateFloor().Create();
            europeanFactory.CreateWindow().Create();
            europeanFactory.CreateDoor().Create();

            //Modern style house
            AbstractFactory modernizationFactory = new ModernizationFactory();
            modernizationFactory.CreateRoof().Create();
            modernizationFactory.CreateFloor().Create();
            modernizationFactory.CreateWindow().Create();
            modernizationFactory.CreateDoor().Create();

            Console.Read();
            #endregion
        }
    }

The operation results are as follows:

2.6 abstract factory should respond to the change of demand

Suppose my sister looks at our house very well. She wants to have a classical style house. How to deal with it?

    class Program
    {
        /// <summary>
        /// Roof abstract class. The roof of a subclass must inherit this class.
        /// </summary>
        public abstract class Roof
        {
            /// <summary>
            /// Building roof
            /// </summary>
            public abstract void Create();
        }

        /// <summary>
        /// Floor abstract class. The floor of a subclass must inherit this class.
        /// </summary>
        public abstract class Floor
        {
            /// <summary>
            /// Create floor
            /// </summary>
            public abstract void Create();
        }

        /// <summary>
        /// Window abstract class, the window of subclass must inherit this class.
        /// </summary>
        public abstract class Window
        {
            /// <summary>
            /// Create windows
            /// </summary>
            public abstract void Create();
        }

        /// <summary>
        /// Door abstract class, the door of a subclass must inherit this class.
        /// </summary>
        public abstract class Door
        {
            /// <summary>
            /// Building doors
            /// </summary>
            public abstract void Create();
        }

        /// <summary>
        /// European roof
        /// </summary>
        public class EuropeanRoof : Roof
        {
            public override void Create()
            {
                Console.WriteLine("Creating a European roof");
            }
        }

        /// <summary>
        /// European flooring
        /// </summary>
        public class EuropeanFloor : Floor
        {
            public override void Create()
            {
                Console.WriteLine("Create European flooring");
            }
        }

        /// <summary>
        ///European windows
        /// </summary>
        public class EuropeanWindow : Window
        {
            public override void Create()
            {
                Console.WriteLine("Creating European windows");
            }
        }

        /// <summary>
        /// European doors
        /// </summary>
        public class EuropeanDoor : Door
        {
            public override void Create()
            {
                Console.WriteLine("Creating European style doors");
            }
        }

        /// <summary>
        /// Modern roof
        /// </summary>
        public class ModernizationRoof : Roof
        {
            public override void Create()
            {
                Console.WriteLine("Creating a modern roof");
            }
        }

        /// <summary>
        /// Modern flooring
        /// </summary>
        public class ModernizationFloor : Floor
        {
            public override void Create()
            {
                Console.WriteLine("Create modern flooring");
            }
        }

        /// <summary>
        /// Modern windows
        /// </summary>
        public class ModernizationWindow : Window
        {
            public override void Create()
            {
                Console.WriteLine("Creating modern windows");
            }
        }

        /// <summary>
        /// Modern doors
        /// </summary>
        public class ModernizationDoor : Door
        {
            public override void Create()
            {
                Console.WriteLine("Creating modern doors");
            }
        }

        /// <summary>
        ///Classical roof
        /// </summary>
        public class ClassicalRoof : Roof
        {
            public override void Create()
            {
                Console.WriteLine("Create a classic roof");
            }
        }

        /// <summary>
        /// Classical floor
        /// </summary>
        public class ClassicalFloor : Floor
        {
            public override void Create()
            {
                Console.WriteLine("Create a classic floor");
            }
        }

        /// <summary>
        /// Classical windows
        /// </summary>
        public class ClassicalWindow : Window
        {
            public override void Create()
            {
                Console.WriteLine("Create classic windows");
            }
        }

        /// <summary>
        /// Classical door
        /// </summary>
        public class ClassicalDoor : Door
        {
            public override void Create()
            {
                Console.WriteLine("Creating classic doors");
            }
        }

        /// <summary>
        /// Abstract factory class, which provides the interface to create different types of houses.
        /// </summary>
        public abstract class AbstractFactory
        {
            //The abstract factory provides the interface to create a series of products. The interface to create roofs, floors, windows and doors is shown here.
            public abstract Roof CreateRoof();
            public abstract Floor CreateFloor();
            public abstract Window CreateWindow();
            public abstract Door CreateDoor();
        }

        /// <summary>
        /// European style house factory, responsible for creating European style house.
        /// </summary>
        public class EuropeanFactory : AbstractFactory
        {
            //Making European roof
            public override Roof CreateRoof()
            {
                return new EuropeanRoof();
            }

            //Making European floor
            public override Floor CreateFloor()
            {
                return new EuropeanFloor();
            }

            //Making European windows
            public override Window CreateWindow()
            {
                return new EuropeanWindow();
            }

            //Making European doors
            public override Door CreateDoor()
            {
                return new EuropeanDoor();
            }
        }

        /// <summary>
        /// Now style house factory, responsible for creating modern style house.
        /// </summary>
        public class ModernizationFactory : AbstractFactory
        {
            //Making modern roofs
            public override Roof CreateRoof()
            {
                return new ModernizationRoof();
            }

            //Making modern flooring
            public override Floor CreateFloor()
            {
                return new ModernizationFloor();
            }

            //Making modern windows
            public override Window CreateWindow()
            {
                return new ModernizationWindow();
            }

            //Making modern doors
            public override Door CreateDoor()
            {
                return new ModernizationDoor();
            }
        }

        /// <summary>
        /// The factory of classical houses, responsible for creating classical houses.
        /// </summary>
        public class ClassicalFactory : AbstractFactory
        {
            //Create a classic roof
            public override Roof CreateRoof()
            {
                return new ClassicalRoof();
            }

            //Create a classic floor
            public override Floor CreateFloor()
            {
                return new ClassicalFloor();
            }

            //Create classic windows
            public override Window CreateWindow()
            {
                return new ClassicalWindow();
            }

            //Create a classic door
            public override Door CreateDoor()
            {
                return new ClassicalDoor();
            }
        }

        static void Main(string[] args)
        {
            #region Abstract factory pattern
            //European style house
            AbstractFactory europeanFactory = new EuropeanFactory();
            europeanFactory.CreateRoof().Create();
            europeanFactory.CreateFloor().Create();
            europeanFactory.CreateWindow().Create();
            europeanFactory.CreateDoor().Create();

            //Modern style house
            AbstractFactory modernizationFactory = new ModernizationFactory();
            modernizationFactory.CreateRoof().Create();
            modernizationFactory.CreateFloor().Create();
            modernizationFactory.CreateWindow().Create();
            modernizationFactory.CreateDoor().Create();

            //Classical house
            AbstractFactory classicalFactory = new ClassicalFactory();
            classicalFactory.CreateRoof().Create();
            classicalFactory.CreateFloor().Create();
            classicalFactory.CreateWindow().Create();
            classicalFactory.CreateDoor().Create();

            Console.Read();
            #endregion
        }
    }

The operation results are as follows:

As can be seen from the above code, five classes need to be added: four classes create specific products of classical style roof, floor, window and door respectively, and the other is the factory class of classical style house, which is responsible for creating

A house in classical style.

As can be seen from the above code, the abstract factory supports the opening and closing principle (open to extension and closed to modification) for the changes of series products, which is very simple to expand. However, the abstract factory for adding new products

In this case, the principle of opening and closing is not supported, because the abstract base class AbstractFactory for creating series of products needs to be modified, and the creation method of corresponding products is added, which is also the disadvantage of abstract factory.

III. key points of the realization of abstract factory

1) if there is no response to the demand change of "multi series object creation", it is not necessary to use AbstractFactory mode. At this time, it is OK to use simple factory mode.

2) "series object" refers to the relationship between these objects, such as the dependence of "road" and "house" in the game development scene, and the dependence of "road" and "tunnel".

3) AbstractFactory mode is mainly to cope with the demand change of "new series", and its disadvantage is that it is difficult to cope with the demand change of "new object".

4) AbstractFactory mode is often combined with FactoryMethod mode to cope with the change of "object creation" requirements.

3.1 advantages of abstract factory mode

Abstract factory pattern delays the creation of series products to subclasses of specific factories. When we declare factory class variables, we use abstract types. Similarly, product types are also abstract types,

This can reduce the dependence between client code and specific product class as much as possible, thus reducing the coupling degree of the system. The coupling degree is reduced, which is more beneficial for later maintenance and expansion. This is abstraction

The advantages of the factory model.

It may be said that the specific factory class will be used in the Main method (client), right. In fact, we can move this part out through the. Net configuration file and put the dependency relationship into the configuration file

Parts. If there are new requirements, we only need to modify the configuration file, and there is no need to modify the code, so that the customer code is more stable. The dependency relationship will certainly exist. What we need to do is to reduce the dependency and try to complete

It's hard and unrealistic to get rid of.

3.2 disadvantages of abstract factory mode

There are advantages and disadvantages, because each mode has its scope of use, or the problem that cannot be solved is the disadvantages. Abstract factory pattern is difficult to support the change of adding new products because of abstract factory

The set of products that can be created has been determined in the interface. If new products need to be added, the interface of the abstract factory must be modified at this time, which involves the change of the abstract factory class and all its subclasses

It also violates the principle of opening and closing.

3.3 usage scenarios of abstract factory mode

If the system needs multiple sets of code solutions, and there are many interrelated product types in each set of code solutions, and a set of products can be used interchangeably in the system

In this mode, the client does not need to rely on the specific implementation.

IV. implementation of abstract factory pattern in. NET

Microsoft's class library has developed for so many years, and the design pattern has a large number of applications in it. Abstract factory pattern is also widely used in. NET class library, such as types related to operation database. This class is

System.Data.Common.DbProviderFactory, located in the System.Data.dll assembly. This class plays the role of an abstract factory in the abstract factory pattern. We can use the ILSpy decompiler to check

See the implementation of this class:

/ / / act as an abstract factory
/ / / set of objects needed to create a connection to the database
/ / / this object collection includes DbConnection object (abstract product class), DbCommand class and DbDataAdapter class. Methods in this abstract class need to be implemented for different specific factories.

    public abstract class DbProviderFactory
    {
        public virtual bool CanCreateDataSourceEnumerator
        {
            get
            {
                return false;
            }
        }

        public virtual DbCommand CreateCommand()
        {
            return null;
        }

        public virtual DbCommandBuilder CreateCommandBuilder()
        {
            return null;
        }

        public virtual DbConnection CreateConnection()
        {
            return null;
        }

        public virtual DbConnectionStringBuilder CreateConnectionStringBuilder()
        {
            return null;
        }

        public virtual DbDataAdapter CreateDataAdapter()
        {
            return null;
        }

        public virtual DbParameter CreateParameter()
        {
            return null;
        }

        public virtual CodeAccessPermission CreatePermission(PermissionState state)
        {
            return null;
        }

        public virtual DbDataSourceEnumerator CreateDataSourceEnumerator()
        {
            return null;
        }
    }

The DbProviderFactory class is an abstract factory class, which provides an interface for the collection of objects needed to create a database connection. The actual creation is carried out in its subclass factory. Microsoft uses

The SQL Server database, therefore, provides a specific factory implementation of connecting SQL server data. The specific code can be viewed with the decompiler tool.

SqlClientFactory acts as a specific factory to create the objects needed to connect to SQL Server data:

    public sealed class SqlClientFactory : DbProviderFactory, IServiceProvider
    {
        public static readonly SqlClientFactory Instance = new SqlClientFactory();

        public override bool CanCreateDataSourceEnumerator
        {
            get
            {
                return true;
            }
        }

        private SqlClientFactory()
        {
        }

        public override DbCommand CreateCommand()
        {
            return new SqlCommand();
        }

        public override DbCommandBuilder CreateCommandBuilder()
        {
            return new SqlCommandBuilder();
        }

        public override DbConnection CreateConnection()
        {
            return new SqlConnection();
        }

        public override DbConnectionStringBuilder CreateConnectionStringBuilder()
        {
            return new SqlConnectionStringBuilder();
        }

        public override DbDataAdapter CreateDataAdapter()
        {
            return new SqlDataAdapter();
        }

        public override DbParameter CreateParameter()
        {
            return new SqlParameter();
        }

        public override CodeAccessPermission CreatePermission(PermissionState state)
        {
            return new SqlClientPermission(state);
        }

        public override DbDataSourceEnumerator CreateDataSourceEnumerator()
        {
            return SqlDataSourceEnumerator.Instance;
        }

        object IServiceProvider.GetService(Type serviceType)
        {
            object result = null;
            if (serviceType == GreenMethods.SystemDataCommonDbProviderServices_Type)
            {
                result = GreenMethods.SystemDataSqlClientSqlProviderServices_Instance();
            }
            return result;
        }
    }

OdbcFactory is also a specific factory class:

    public sealed class OdbcFactory : DbProviderFactory
    {
        public static readonly OdbcFactory Instance = new OdbcFactory();

        private OdbcFactory()
        {
        }

        public override DbCommand CreateCommand()
        {
            return new OdbcCommand();
        }

        public override DbCommandBuilder CreateCommandBuilder()
        {
            return new OdbcCommandBuilder();
        }

        public override DbConnection CreateConnection()
        {
            return new OdbcConnection();
        }

        public override DbConnectionStringBuilder CreateConnectionStringBuilder()
        {
            return new OdbcConnectionStringBuilder();
        }

        public override DbDataAdapter CreateDataAdapter()
        {
            return new OdbcDataAdapter();
        }

        public override DbParameter CreateParameter()
        {
            return new OdbcParameter();
        }

        public override CodeAccessPermission CreatePermission(PermissionState state)
        {
            return new OdbcPermission(state);
        }
    }

Of course, we also have the OleDbFactory type, which is responsible for specific database operations. DbProviderFactory is the AbstractFactory type in the abstract factory pattern UML, and other specific factory classes

Type inherits from type DbProviderFactory.

V. summary

Learning design pattern can't be dead learning. We should grasp the core points and use scenarios. The key points are the basic principles of object-oriented design pattern. With principles, we will not deviate from each other when we think about problems, and then we will carefully grasp the

Use scenarios and problems to be solved. Write more code and look at Net class library. It is the best teaching material.

Tags: C# Windows Database SQL

Posted on Tue, 14 Jan 2020 00:39:26 -0500 by xgd