• 设计模式之-工厂模式


    前言

    回顾上篇的设计模式之-简单工厂模式 我们可以从中发现一些问题。

    先看看以计算器为例的简单工厂的结构图如下:

    那此时我们换成工厂模式呢?我们先看看工厂的结构图:

    承接上篇计算器为例,我们需要新建一个工厂接口

     /// <summary>
        /// 构建一个工厂接口
        /// </summary>
        interface IFactory
        {
            Operaion CreateOperation();
        }

    然后呢,为加减乘法各建一个具体的工厂实现接口

     //然后加减乘法各建一个具体的工厂实现接口
        class AddFactory : IFactory
        {
            public Operaion CreateOperation()
            {
                return new OpertionAdd();
            }
        }
        class SubFactory : IFactory
        {
            public Operaion CreateOperation()
            {
                return new OperationSub();
            }
        }
        class MulFactory : IFactory
        {
            public Operaion CreateOperation()
            {
                return new OperationMul();
            }
        }
        class DivFactory : IFactory
        {
            public Operaion CreateOperation()
            {
                return new OperationDiv();
            }
        }

    客户端调用

     static void Main(string[] args)
            {
                try
                {
                    Console.Write("请输入数字A:");
                    string strNumberA = Console.ReadLine();
                    Console.Write("请选择运算符号(+、-、*、/):");
                    string strOperate = Console.ReadLine();
                    Console.Write("请输入数字B:");
                    string strNumberB = Console.ReadLine();
                    //调用工厂进行计算
                    IFactory operFactory = new AddFactory();
                    Operaion oper = operFactory.CreateOperation();
                    oper.NumberA =double.Parse(strNumberA);
                    oper.NumberB =double.Parse(strNumberB);
                    //返回计算结果
                    var  strResult = oper.GetResult();
                    Console.WriteLine("结果是:" + strResult);
                    Console.ReadKey();
                }
                catch (Exception ex)
                {
                    Console.WriteLine("您的输入有错:" + ex.Message);
                }
            }

    Why?为什么要这么写呢?上一篇的简单工厂已经很容易就实现了这个效果,为什么还要新加这个工厂来“复杂”化这个问题呢?

    其实不然,简单工厂模式的最大优点在于工厂类中包含了必要的逻辑判断,根据客户端的选择条件动态实例化相关的类,对于客户端来说,去除了具体产品的依赖。

    就像计算器,客户端不用管该用哪个类的实例,只需要把"+"给工厂,工厂自动就给出了相应的实例,客户端只要去做运算就可以了。但问题也在这里,如果要加一个‘求M数的N次方’功能,我们是一定要给运算工厂类的方法里加‘Case’分支条件的,既是修改了原有的类。这样就违背了我们开放-封闭原则。于是工厂方法就来了

    这样的话,我们要增加‘求M数的N次方’的功能时,就不需要更改原有的工厂类了,只需要增加此功能的运算类和相应的工厂类就可以了。这就完全符合开放-封闭原则。

    巩固

     以大学生学习‘雷锋’好人好事为例。首先是雷锋类:拥有扫地、洗衣、买米等方法

     //雷锋类
        class LeiFeng
        {
            public void Sweep()
            {
                Console.WriteLine("扫地");
            }
            public void Wash()
            {
                Console.WriteLine("洗衣");
            }
            public void BuyRice()
            {
                Console.WriteLine("买米");
            }
        }

    然后‘学雷锋大学生’类继承‘雷锋’类

    /// <summary>
        /// 学雷锋的大学生,继承‘雷锋’
        /// </summary>
        class Undergraduate : LeiFeng
        { }

    然后客户端实现

                    LeiFeng xueleifeng = new Undergraduate();
                    xueleifeng.BuyRice();
                    xueleifeng.Sweep();
                    xueleifeng.Wash();

    有一个问题,如果有三个人去学‘雷锋做好事,该怎么写呢?’

    难道是写成?

          LeiFeng xueleifeng = new Undergraduate();
                    xueleifeng.BuyRice();
                    LeiFeng xueleifeng2 = new Undergraduate();
                    xueleifeng.Sweep();
                    LeiFeng xueleifeng3 = new Undergraduate();
                    xueleifeng.Wash();

    此时,就非常不合适了,老人不需要知道是谁来做好事,他只需要知道学雷锋的人来帮忙就可以ile,这样写我们需要更改多个实例化的地方。我们应该增加‘社区志愿者’类

     /// <summary>
        /// 社区志愿者
        /// </summary>
        class Volunteer : LeiFeng
        { }

    再写简单工厂类

    /// <summary>
        /// 简单雷锋工厂
        /// </summary>
        class SimpleFactory
        {
            public static LeiFeng CreateLeiFeng(string type)
            {
                LeiFeng result = null;
                switch (type)
                { 
                    case "学雷锋的大学生":
                        result = new Undergraduate();
                        break;
                    case "社区志愿者":
                        result=new Volunteer();
                        break;
                }
                return  result;
            }
        }

    客户端的代码,如果要换,就只需要换‘学雷锋的大学生为‘社区志愿者’’

                    //简单工厂模式
                    LeiFeng studentA = SimpleFactory.CreateLeiFeng("学雷锋的大学生");
                    studentA.BuyRice();
                    LeiFeng studentB = SimpleFactory.CreateLeiFeng("学雷锋的大学生");
                    studentA.Sweep();
                    LeiFeng studentC = SimpleFactory.CreateLeiFeng("学雷锋的大学生");
                    studentA.Wash();

    好,此时我们就发现,在任何实例化的时候写出这个工厂的代码,这里有重复,就出现了坏的味道,此时,我们再用工厂模式写一遍。

    /// <summary>
        /// 雷锋工厂
        /// </summary>
        interface IFactory
        {
            LeiFeng CreateLeiFeng();
        }
        /// <summary>
        /// 学雷锋的大学生工厂
        /// </summary>
        class UndergraduateFacotry : IFactory
        {
            public LeiFeng CreateLeiFeng()
            {
                return new Undergraduate();
            }
        }
        /// <summary>
        /// 社区志愿者工厂
        /// </summary>
        class VolunteerFactory : IFactory
        {
            public LeiFeng CreateLeiFeng()
            {
                return new Volunteer();
            }
        }

    客户端调用的时候只需要如下就可以了

             //工厂方法模式
                    IFactory factory = new UndergraduateFacotry();//要换成‘社区志愿者’,修改这里即可
                    LeiFeng student = factory.CreateLeiFeng();
                    student.BuyRice();
                    student.Sweep();
                    student.Wash();

    小结

    工厂方法克服了简单工厂违背开放-封闭原则的缺点,又保持了封装对象创建过程的优点。

    但以上并不是最佳做法,利用‘反射’可以解决避免分支判断的问题。

    未完待更新。。。。

  • 相关阅读:
    [C++ Primer Plus] 第4章、复合类型(二)课后习题
    [C++ Primer Plus] 第4章、复合类型(一)程序清单——指针new和delete
    opencv学习之路(28)、轮廓查找与绘制(七)——位置关系及轮廓匹配
    [c/c++] programming之路(20)、字符串(一)
    [Python]基础教程(3)、Python基础语法
    [Python]基础教程(2)、PyCharm安装及中文编码
    opencv学习之路(27)、轮廓查找与绘制(六)——外接圆、椭圆拟合、逼近多边形曲线、计算轮廓面积及长度、提取不规则轮廓
    [Python]基础教程(1)、介绍及环境搭建
    白雪公主与七个爷爷——冲刺日志(第一天)
    白雪公主与七个爷爷——凡事预则立
  • 原文地址:https://www.cnblogs.com/zhangxiaoyong/p/7200450.html
Copyright © 2020-2023  润新知