• 设计模式之简单工厂模式


            大二第一学期开始,一直在自学设计模式。为了巩固学习内容,把自己的理解和想法写了下来,总结了一下知识点,想拿出来和大家分享一下。如果能帮助大家的话,我会非常高兴,同时也欢迎大家指出里面的不足,让我们在一块不断地成长。

          在说设计模式之前,我们不得不提的就是C#语言里面的面向对象,因为面向对象是设计的核心,也是面向对象语言的灵魂和骨架,面向对象的三大特性,封装,继承,多态把程序的耦合度降低,而面向对象的三大特性也是设计模式的基础。

         我们在简单介绍完面向对象语言之后 ,接下来谈一下面向对象语言的优点:

    一、面向对象的优点

    1、易维护

    采用面向对象思想设计的结构,可读性高,耦合度降低,同时由于继承的存在,即使改变需求,那么维护也只是在局部模块,所以维护起来是非常方便和较低成本的。

    2、复用率高

    在设计时,可重用现有的代码(例如:基类),减少代码量,提高程序的可读性

    3、灵活性强

    在软件开发时,我们可以设计接口和抽象类,来定义统一的标准,从而通过重写基类实现对象不同的表现形式,同时由于各模块之间高内聚,低耦合,使得软件的设计和开发更加的灵活多样

    4、易扩展

    由于继承、封装、多态的特性,自然设计出高内聚、低耦合的系统结构,使得系统更灵活、更容易扩展,而且成本较低

    (ps 嘿嘿!上面是对面向对象的简单介绍,建议学习设计模式之前,先把面向对象的知识点复习一下,这样可能会更好哦!建议阅读程杰<大话设计模式>面向对象基础)

    接下来,让我们一起畅想简单工厂模的快乐吧!

    二、简单工厂模式(Simple Factory Pattern)

    (一)介绍:

          简单工厂模式准确来说不能是一个设计模式,说它是一种编程习惯可能更恰当些。因为它至少不是Gof23种设计模式之一。但它在实际的编程中经常被用到,而且思想也非常简单,可以说是工厂方法模式的一个引导,同时也是今后学习其他设计模式的基础。

    (二)引入:

         我们在编程的时候,每当"new"一个对象之后,这个对象就依赖于这个类了。如果在后期的维护过程中由于某些原因需要修改一下这个类,则唯一的做法就是打开源代码,进行修改,修改所有与这个对象有关的操作。这对我们是非常不利的。

        问题出来了:对象不能应对“具体实例化类型”的变化

        解决思路:套用一下李建忠李老师的话,封装变化点,哪里变化,封装哪里。在这个例子中,要实例化的类变了,就将实例化这个操作封装起来,我们可以把"new"这个操作移交一个具体的类,由它去负责根据我们的条件创建具体类的实例,也就是下面要说的“简单工厂模式”。

    举一个现实中的小例子:

           一个人(用户)想到玩具工厂(工厂)去买一个玩具(具体返回类的实例),然后,他就到了这个玩具工厂里面找到销售经理,然后说我要买一个小猫玩具,然后销售经理就会和内部人员交流,最后拿出一个小猫玩具给那个人,但是如果那个人问销售经理要小狗玩具的话,如果工厂也生产这个玩具,那么用户也会得到小狗玩具。

    (三)定义:

    专门定义一个类来负责创建其他类的实例,被创建的实例通常都具有共同的父类或接口。简单工厂模式又称为静态工厂方法(Static Factory Method)模式,属于类的创建型模式,通常根据一个条件(参数)来返回不同的类的实例。

    简单工厂模式的类图:

    (四)参与者:

    工厂角色(Creator):

    是简单工厂模式的核心,它负责实现创建所有具体产品类的实例。工厂类可以被外界直接调用,创建所需的产品对象。

    抽象产品角色(Product):

    是所有具体产品角色的父类,它负责描述所有实例所共有的公共接口。

    具体产品角色(Concrete Product):

    继承自抽象产品角色,一般为多个,是简单工厂模式的创建目标。工厂类返回的都是该角色的某一具体产品。 

    理论知识可能有点枯燥了,让我们来段代码加深一下理解:(ps 代码胜过一切,实践出真知)

    现在让我们写一个最常用的代码,就是实现一个简单计算器的代码:

    public  class Operation
        {
           public  static  double GetResult(double NumberA,double NumberB,string operate)
    
            {
    
              double result=0;
    
              switch(operate){
    
                 case "+":
                 result=NumberA+NumberB;
                 break;
    case "-": result=NumberA-NumberB; break;

    case "*": result=NumberA*NumberB; break;

    case "/": result=NumberA/NumberB; break; } return result; } }

    写完这个运算类 我们可以复用此方法 ,可以在web版,手机等 写计算器,但是如果我希望计算器在加一个求平方根的功能,我们只需要在switch里加个语句,似乎很简单,但是你加个语句 却要让加减乘除一起编译一遍 ,所以我们需要对上面进行修改,将每个方法分离,于是我们来用简单工厂模式(SimpleFactory)。

    (1) 定义运算类:

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.Threading.Tasks;
    
    namespace 工厂模式
    {
      public class Operation //运算类的书写,为基类,抽象产品类
        {
          
              private double number1=0;
              private double number2=0;//声明数字一和数字二,私有类型,通过属性进行赋值
    
              public double Number1
              {
                  get { return number1; }
                  set { number1 = value; }
              }
    
              public double Number2
              { 
              get {return number2;}
              set {number2 = value;}
              }
    
              public virtual double GetResult()//虚方法,方法的重写,为了接收计算的结果
              {
                  double result = 0; ;
                  return result;
              }
        }
    
      class OprationAdd : Operation //加法类,此类继承基类运算类,具体产品类
      {
          public override double GetResult() //方法的重写,此处重写基类方法
          {
              double result = 0;
              result = Number1 + Number2;//结果得到一个值
              return result;  //将结果返回
          }
      }
    
      class OprationSub : Operation //减法类,此类继承基类运算类
      {
          public override double GetResult() 
          {
              double result = 0;
              result = Number1 - Number2;
              return result;
          }
      }
    
      class OprationMul : Operation  //乘法类,此类继承基类运算类
      {
          public override double GetResult()
          {
              double result = 0;
              result = Number1 * Number2;
              return result;
          }
      }
    
      class OprationDiv : Operation //除法类,此类继承基类运算类
      {
          public override double GetResult()
          {
              double result = 0;
              if (Number2 != 0)
              {
                  result = Number1 / Number2;
                  return result;
              }
              else
              {
                  throw new Exception("除数不能为0");
              }
              
          }
      }
    }

    (2) 定义简单工厂类(把实例对象的过程封装到一个类里面)

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.Threading.Tasks;
    
    namespace 工厂模式
    {
       //现在存在的问题是如何去实例化一个对象,将来如果要实例化一个开根运算,这是容易变化的点,可以建造一个工厂来实现它。
       public  class OperationFactory //建造一个工厂类,里面生产各种形式的运算
        {
           public static Operation createOperate(string oprate)//声明一个名称为createOperate的静态方法,并且返回值为Operation类型
           
           {
               Operation oper = null;
               switch (oprate)
               { 
                   case"+":
                       oper = new OprationAdd();
                       break;
    
                   case "-":
                       oper = new OprationSub();
                       break;
    
                   case "*":
                       oper = new OprationMul();
                       break;
    
                   case "/":
                       oper = new OprationDiv();
                       break;
               }
               return oper;
           }
        }
    }

    (3)  我们在客户端实现一下计算器的功能:

     using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.Threading.Tasks;
    
    namespace 工厂模式
    {
        class Program
        {
            static void Main(string[] args)
            {
                
                Operation oper;
                
                Console.WriteLine("请输入运算符号+,-,*,/:");
                oper = OperationFactory.createOperate(Console.ReadLine());//调用工厂中的creatOperate方法,参数为string oprate
    
                Console.WriteLine("请输入第一个数字:");
                oper.Number1 = int.Parse(Console.ReadLine());
    
                Console.WriteLine("请输入第二个数字:");
                oper.Number2 = int.Parse(Console.ReadLine());//运算类中的数字1 2接收用户赋过来的值
    
                double result = oper.GetResult();//声明一个double类型的变量,用于接收运算类里面得到的运算结果
                Console.WriteLine("和为{0}",result);
                Console.ReadLine();
            } 
        }
    }

    来让我们看一下这段代码的类图:

    事物都存在两面性,最后来我们看一下简单工厂模式的优缺点和使用场景:

    (1)优点:

      1 实现了对象创建和使用的分离

      2 客户端无须知道所创建的具体产品类的类名,只需要知道具体产品类所对应 的参数即可

      3 通过引入配置文件,可以在不修改任何客户端代码的情况下更换和增加新的具体产品类,在一定程度上提高了系统的灵活性

    (2)缺点:

       1 工厂类集中了所有产品的创建逻辑,职责过重,一旦不能正常工作,整个系统都要受到影响

       2 增加系统中类的个数(引入了新的工厂类),增加了系统的复杂度和理解难度

       3 系统扩展困难,一旦添加新产品不得不修改工厂逻辑

       4 由于使用了静态工厂方法,造成工厂角色无法形成基于继承的等级结构,工厂类不能得到很好地扩展

    (3)适用场景:

     工厂类负责创建的对象比较少,由于创建的对象较少,不会造成工厂方法中的业务逻辑太过复杂

     客户端只知道传入工厂类的参数,对于如何创建对象并不关心

           好啦,今天由于是第一次写设计模式方面的博客,说的比较多一点,(哈哈!可能太兴奋了吧)!今后让我们一起在探索中不断进步吧!

     

    参考资料:《大话设计模式》清华大学出版社 程杰著

  • 相关阅读:
    观察者模式
    简单工厂
    一个数组先按值排序,如果它的值有相同,就再按键排序(转)
    Python 一些好玩的函数
    python 一些基础知识
    python3 写CSV文件多一个空行的解决办法
    pandas学习笔记
    pycharm2017.1破解方法
    python的Debug调试
    python中字典的陷阱
  • 原文地址:https://www.cnblogs.com/wyh19941210/p/5437435.html
Copyright © 2020-2023  润新知