• 设计模式


    工厂模式是创建型模式之一,其主要功能都是帮助我们把对象的实例化部分分离出来,降低系统中代码耦合度,增强了系统的扩展性,并将对象的创建过程延迟到子类进行

    工厂模式

    分类:

    • 简单工厂模式(Simple Factory):只有一个工厂,通过向工厂传参来选择工厂所要生产的产品
    • 工厂方法模式(Factory Method):允许多个工厂,但一个工厂只生产一种产品,通过不同的工厂类型来选择所要生产的产品
    • 抽象工厂模式(Abstract Factory):允许多个工厂,一个工厂允许生产多种产品,通过工厂实例的不同方法来选择所要生产的产品

    Github源码:

    简单工厂模式

    含义:只有一个工厂类,客户端向工厂传递所需产品名,工厂生产产品交予客户

    实现过程:

    • 理论性:创建产品的抽象类做为产品基类,产品类(派生类)继承该基类并实现各自方法。工厂类 负责接收客户端传入的参数(产品名),根据参数选择对应产品类进行实例化,最终返回给客户端
    • 比喻:客户去印刷厂印刷书籍,客户只需要告诉印刷厂其需求(书名、材质 ..),印刷厂根据该需求选择印刷对应的书籍,最终交予客户

    优缺点:

    • 优点:
      • 客户端无须知道所创建的具体产品类的创建细节,只需将产品名参数传递到工厂类即可实现创建并使用
      • 添加新类即可实现新产品的类,无需对客户端进行大改动
    • 缺点:
      • 随着产品的增加,对应产品类数量增加,增加了系统复杂度
      • 新增加产品类都会修改工厂类,违背 “开闭原则”
      • 由于工厂类集中了所有产品创建逻辑,一旦不能正常工作,整个系统都要受到影响

    项目示例:

    简单工厂模式实现加减乘除运算,工厂类OperationFactory 根据传入的运算符字符("+"、"-" ..),自动选择实例化的运算类并返回,实现计算:

    // 运算基类(抽象产品类):
    // --------------------
    public class Operation
    {
        public double NumberA { get; set; }
        public double NumberB { get; set; }
    
        public virtual double GetResult()
        {
            double result = 0;
            return result;
        }
    }
    
    // 运算符派生类(具体产品类):
    // ------------------------
    class OperationAdd : Operation
    {
        public override double GetResult()
        {
            double result = 0;
            result = NumberA + NumberB;
            return result;
        }
    }
    class OperationSub : Operation
    {
        public override double GetResult()
        {
            double result = 0;
            result = NumberA - NumberB;
            return result;
        }
    }
    class OperationMul : Operation
    {
        public override double GetResult()
        {
            double result = 0;
            result = NumberA * NumberB;
            return result;
        }
    }
    class OperationDiv : Operation
    {
        public override double GetResult()
        {
            double result = 0;
            if (NumberB == 0)
                throw new Exception("除数不可为 0");
            result = NumberA / NumberB;
            return result;
        }
    }
    
    // 工厂类:
    // ------
    public class OperationFactory
    {
        public static Operation CreateOperate(string operate)
        {
            //根据传入的参数operate选择实例化的类
            Operation oper = null;
            switch (operate)
            {
                case "+":
                    oper = new OperationAdd();
                    break;
                case "-":
                    oper = new OperationSub();
                    break;
                case "*":
                    oper = new OperationMul();
                    break;
                case "/":
                    oper = new OperationDiv();
                    break;
            }
            return oper;
        }
    }
    
    // 客户端:
    // ------
    class Test
    {
        static void Main(string[] args)
        {
    		//创建运算基类的对象,传入字符串到工厂类,返回对应实类的实例对象
            Operation oper;        
            oper = OperationFactory.CreateOperate("+");
            oper.NumberA = 4;  oper.NumberB = 2;
            double result = oper.GetResult();
            Console.WriteLine(result);		// 6
    
            oper = OperationFactory.CreateOperate("-");
            oper.NumberA = 4; oper.NumberB = 2;
            result = oper.GetResult();
            Console.WriteLine(result);		// 2
    
            oper = OperationFactory.CreateOperate("/");
            oper.NumberA = 4; oper.NumberB = 2;
            result = oper.GetResult();
            Console.WriteLine(result);		// 2
        }
    }
    

    UML图

    工厂方法模式

    含义:允许多个工厂,但一个工厂只生产一种产品,通过不同的工厂类型来选择所要生产的产品。也可以说:定义一个创建对象的接口,让其子类自己决定实例化哪一个工厂类,即使其创建过程延迟到子类进行

    实现过程:

    • 理论性:创建抽象工厂接口,创建各类产品的工厂类继承该接口并实现各自方法。客户端选择所需产品的工厂,对应工厂实现生产并返还
    • 比喻:客户去印刷全彩书刊,需要找到对应的全彩书刊印刷厂,该工厂拥有印刷该类书籍的方法,因此可执行印刷功能并将产品交予客户

    优缺点:

    • 优点:
      • 用户只需关心产品对应工厂而无需知道创建细节、产品名
      • 添加新产品只需添加具体工厂类、产品类即可,可拓展性好,符合 “开放封闭原则”
      • 由于一个工厂只生产一种产品,因此也符合“单一职责原则”
    • 缺点:
      • 随着产品的增加,对应工厂类、产品类数量增加,增加了系统复杂度

    项目示例:

    对上节简单工厂方法的项目示例做修改,实现工厂方法模式:抽象产品类、各运算类保持不变,添加抽象工厂接口,并由该接口派生出各类计算方法的工厂类,客户端通过工厂类即可实现计算功能

    #region 上述的运算基类(抽象产品类) + 运算符派生类(具体产品类)
    //...
    #endregion
    
    // 抽象工厂接口:
    // -----------
    interface IFactory
    {
        Operation CreateOperation();
    }
    
    // 各运算工厂类:
    // -----------
    // 加法工厂
    class AddFactory : IFactory
    {
        public Operation CreateOperation()
        {
            return new OperationAdd();
        }
    }
    // 减法工厂
    class SubFactory : IFactory
    {
        public Operation CreateOperation()
        {
            return new OperationSub();
        }
    }
    // 乘法工厂
    class MulFactory : IFactory
    {
        public Operation CreateOperation()
        {
            return new OperationMul();
        }
    }
    // 除法工厂
    class DivFactory : IFactory
    {
        public Operation CreateOperation()
        {
            return new OperationDiv();
        }
    }
    
    // 客户端:
    // ------
    class Test
    {
        static void Main(string[] args)
        {
    		//用户选择产品对应的工厂进行生产
            IFactory operFactory = new AddFactory();
            Operation oper = operFactory.CreateOperation();
            oper.NumberA = 4;   oper.NumberB = 2;
            double result = oper.GetResult();		//6
        }
    }
    

    UML图

    抽象工厂模式

    含义:允许多个工厂,一个工厂允许生产多种产品,通过工厂实例的不同方法来选择所要生产的产品。也可以说:提供一个创建一系列相关或相互依赖对象的接口,而无须指定它们具体的类

    实现过程:

    • 理论性:抽象产品接口->具体产品类,抽象工厂接口->具体工厂类,客户端创建工厂、选择生产产品
    • 比喻:显示器(抽象产品接口)的产品有苹果显示器、戴尔显示器(具体产品类),主机的产品也有苹果和戴尔;生产电脑设备的工厂(抽象工厂接口)有苹果工厂和戴尔工厂(具体工厂类),客户可以选择苹果或者戴尔电脑工厂,再选择要生产该品牌的显示器或是主机

    扩展:

    • 产品族:具有相同属性的同类型产品,如戴尔显示器、戴尔主机都属于戴尔
    • 产品等级结构:产品的继承结构,如产品抽象类(显示器),其具体产品类有戴尔显示器、苹果显示器,抽象类与产品类之间构成了产品等级结构

    优缺点:

    • 优点:
      • 将一个系列的产品族(戴尔的显示器、主机..)统一到对应工厂进行创建,便于客户端直接使用同一产品族的工厂进行生产操作
      • 较比与工厂方法模式,减少了工厂类和具体产品的类添加
    • 缺点:
      • 产品族扩展困难(例如添加苹果ipad,则需要对产品的抽象、具体类修改,工厂的抽象、具体类修改)

    项目示例:

    采用抽象工厂模式实现苹果、戴尔电脑的生产工厂:创建两个抽象产品接口(显示器、主机),根据该接口实现具体产品类(苹果显示器、苹果主机、戴尔..);创建抽象工厂接口(电脑工厂),根据该接口实现具体工厂类(苹果电脑工厂、戴尔电脑工厂);最终在客户端进行工厂创建、生产产品

    // 抽象产品类:
    // ----------
    // 抽象产品 - 显示器
    interface IDisplay
    {
        void Show();
    }
    // 抽象产品 - 主机
    interface IMainFrame
    {
        void Open();
    }
    
    // 具体产品类:
    // ----------
    // 具体产品 - 苹果显示器
    class AppleDisplay : IDisplay
    {
        public void Show()
        {
            Console.WriteLine("苹果显示器正常工作!");
        }
    }
    //具体产品 - 戴尔显示器
    class DellDisplay : IDisplay
    {
        public void Show()
        {
            Console.WriteLine("戴尔显示器正常工作!");
        }
    }
    // 具体产品 - 苹果主机
    class AppleMainFrame : IMainFrame
    {
        public void Open()
        {
            Console.WriteLine("苹果主机启动成功!");
        }
    }
    // 具体产品 - 戴尔主机
    class DellMainFrame : IMainFrame
    {
        public void Open()
        {
            Console.WriteLine("戴尔主机启动成功!");
        }
    }
    
    // 抽象工厂类:
    // ----------
    // 抽象电脑工厂
    interface IComputerFactory
    {
        // 生产一个显示器
        IDisplay ProduceADisplay();
    
        // 生产一个主机
        IMainFrame ProduceAMainFrame();
    }
    
    // 具体工厂类:
    // ----------
    // 具体工厂 - 苹果电脑工厂
    class AppleComputerFactory:IComputerFactory
    {
        public IDisplay ProduceADisplay()
        {
            return new AppleDisplay();
        }
    
        public IMainFrame ProduceAMainFrame()
        {
            return new AppleMainFrame();
        }
    }
    // 具体工厂 - 戴尔电脑工厂
    class DellComputerFactory : IComputerFactory
    {
        public IDisplay ProduceADisplay()
        {
            return new DellDisplay();
        }
    
        public IMainFrame ProduceAMainFrame()
        {
            return new DellMainFrame();
        }
    }
    
    // 客户端:
    // ------
    class Client
    {
        static void Main()
        {
            //创建苹果电脑工厂
            IComputerFactory MyAppleFactory = new AppleComputerFactory();
    
            //生产苹果显示器
            IDisplay AppleDisplay = MyAppleFactory.ProduceADisplay();
            AppleDisplay.Show();		//苹果显示器正常工作!
    
            //创建戴尔电脑工厂
            IComputerFactory MyDellFactory = new DellComputerFactory();
    
            //生产戴尔主机
            IMainFrame DellMainFrame = MyDellFactory.ProduceAMainFrame();
            DellMainFrame.Open();		//戴尔主机启动成功!
        }
    }
    

    UML图

    参考

  • 相关阅读:
    Spring Security OAuth2 源码分析
    Spring Security OAuth2 token权限隔离
    Spring Cloud Feign 使用OAuth2
    Spring Security OAuth2 授权码模式
    全链路追踪spring-cloud-sleuth-zipkin
    Spring Security OAuth2 授权失败(401) 问题整理
    使用ShardingJdbc分表
    Kubectl常用命令
    Spring Cloud Zuul实现IP访问控制
    一次非核心接口(信息提示类)被刷引发的思考
  • 原文地址:https://www.cnblogs.com/SouthBegonia/p/11967904.html
Copyright © 2020-2023  润新知