Home > Article > Backend Development > .NET Factory Method Pattern Explanation
Introduction to the Factory Method Pattern:
The meaning of the Factory Method pattern is to define a factory interface that creates product objects, deferring the actual creation work to subclasses. The core factory class is no longer responsible for the creation of products. In this way, the core class becomes an abstract factory role, responsible only for the interfaces that specific factory subclasses must implement. The benefit of further abstraction is that the factory method pattern allows the system to operate without modifying the specific factory role. Introducing new products.
Factory method pattern structure diagram:
Role classification:
Abstract factory role: It is the core of the factory method pattern and has nothing to do with the application. Any factory class for objects created in the pattern must implement this interface.
Concrete Factory Role: This is a concrete factory class that implements the Abstract Factory interface, contains logic closely related to the application, and is called by the application to create product objects
Abstract Product Role: The super type of the object created by the Factory Method pattern, That is, the common parent class or commonly owned interface of product objects. In the picture above, this character is Light.
Concrete product role: This role implements the interface defined by the abstract product role. A specific product is created by a specific factory, and there is often a one-to-one correspondence between them.
Introducing practical examples:
In the previous blog post Simple Factory Pattern, the following implementation was implemented using the simple factory pattern: If there is a tenant management system, the tenant types in it are variable, and the rent of each tenant type is There are differences in the calculation formulas. For example: the rent amount for type A residents = number of days * unit price + performance * 0.005; the rent amount for type B residents = month * (monthly price + performance * 0.001) Although we have achieved the customer's needs here, but If the customer later needs to add a C-type store and a D-type store, and their algorithm requirements are different, at this time we need to create C and D-type stores, inherit the Ishop interface, implement the methods inside, and also need to Continue to modify the factory class and add cases in switch to capture and create corresponding store objects. Once such a situation occurs, it will be detrimental to the scalability of the program and the later maintenance of the project.
1. Analysis: Stores have common behavioral characteristics and must perform store rent calculation behavior. We abstracted Ishop, which contains the behavior of calculating store rent method to be implemented.
using System; using System.Collections.Generic; using System.Linq; using System.Text; namespace FactoryEntiy { public interface Ishop { double Getrent(int days, double dayprice, double performance); } }
2. We implement the methods in the Isho interface and create type A and B stores.
using FactoryEntiy; using System; using System.Collections.Generic; using System.Linq; using System.Text; namespace ProductEnity { /// <summary> /// 继承商店接口,实现里面的行为方法,即算法 /// </summary> public class Ashop:Ishop { /// <summary> /// /// A类型商店租金额,天数*单价+绩效*0.005 /// </summary> /// <param name="days">天数</param> /// <param name="dayprice">每天单价</param> /// <param name="performance">日平均绩效</param> /// <returns></returns> public double Getrent(int days, double dayprice, double performance) { Console.WriteLine("A商店的租金算法"); return days * dayprice + performance * 0.01; } } }
using FactoryEntiy; using System; using System.Collections.Generic; using System.Linq; using System.Text; namespace ProductEnity { /// <summary> /// 继承商店接口,实现里面的行为方法,即算法 /// </summary> public class Bshop:Ishop { /// <summary> /// B类型商店的租金=月份*(每月价格+performance*0.001) /// </summary> /// <param name="month">月数</param> /// <param name="monthprice">月单价</param> /// <param name="performance">月平均绩效</param> /// <returns></returns> public double Getrent(int month, double monthprice, double performance) { Console.WriteLine("B商店的租金算法"); return month * (monthprice + performance * 0.001); } } }
3. Now consider the circumstances under which to create store entities, calculate rents for different stores, and facilitate future additions and modifications. So we create the IFactroy interface, which contains methods to create store objects to be implemented.
using FactoryEntiy; using System; using System.Collections.Generic; using System.Linq; using System.Text; namespace FactoryMethod { /// <summary> /// 工厂类,创建商店类型实体 /// </summary> public interface IFactory { Ishop CreateShop(); } }
4. Now we can inherit from IFactory and create the corresponding store object in it.
using FactoryEntiy; using FactoryMethod; using ProductEnity; using System; using System.Collections.Generic; using System.Linq; using System.Text; namespace ProductEnity { /// <summary> /// 继承工厂类,创建A类型商店实体 /// </summary> public class CreateBshop : IFactory { public Ishop CreateShop() { return new Ashop(); } } }
using FactoryEntiy; using FactoryMethod; using ProductEnity; using System; using System.Collections.Generic; using System.Linq; using System.Text; namespace ProductEnity { /// <summary> /// 继承工厂类,创建B类型商店实体 /// </summary> public class CreateAshop : IFactory { public Ishop CreateShop() { return new Bshop(); } } }
5. Then judge based on the current store type, which algorithm should be used for this type of store:
using FactoryEntiy; using System; using System.Collections.Generic; using System.Configuration; using System.Linq; using System.Reflection; using System.Text; namespace FactoryMethod.App { class Program { static void Main(string[] args) { string shopname = ConfigurationManager.AppSettings["CreateShopClassName"]; //shopname为创建商店类名称,此处=CreateAshop IFactory af = (IFactory)Assembly.Load("ProductEnity").CreateInstance("ProductEnity." + shopname); //第一个ProductEnity是dll的名称,第二个ProductEnity是项目的命名空间。 Ishop As = af.CreateShop(); double total = As.Getrent(30, 300, 2000); //30 天/100元 日平均绩效为2000 Console.WriteLine("该A类型商店的租金为:" + total); Console.WriteLine("============="); IFactory bf = (IFactory)Assembly.Load("ProductEnity").CreateInstance("ProductEnity." + "CreateBshop"); //CreateBshop可以保存为配置或者存在数据库中, //注意该保存字符串应该与项目中创建的类名一样, //否则反射的方式会找不到该项目下的类。 Ishop Bs = bf.CreateShop(); total = Bs.Getrent(30, 300, 2000); //30 天/100元 日平均绩效为2000 Console.WriteLine("该A类型商店的租金为:" + total); } } }
Here we use reflection to create objects and replace The previous factory class creates objects through switch, which is beneficial to the subsequent addition of new types of stores and algorithm modifications, additions and maintenance. When project requirements change in the future, we only need to re-add C and D type stores to the project and inherit the Ishop implementation. The methods inside, at the same time, add the IFactroy interface, create the corresponding store object, compile the ProductEnity.dll of the project, and then calculate the C, D type store algorithm through reflection, without modifying the original Engineering code.
The structure diagram of the entire project is as follows: