zoukankan      html  css  js  c++  java
  • 设计模式——简单工厂模式

    shanzm-2020年4月1日 22:18:49

    1. 简介

    简单工厂模式(Simple Factory Pattern):定义一个工厂类,根据不同的参数,创建并返回不同的类。其中这些类具有一个公共的父类或是一个接口。

    简单工厂模式不属于GoF四人组提出的23种设计模式,它是最简单的工厂模式。

    简单工厂模式包含类:

    • Factory:工厂类,内部有是个精通的方法,根据参数选择创建的对象

    • Product:抽象产品类,其作为具体产品的父类,负责定义产品的公共接口

    • ConcreteProduct:具体产品类,有多个,都是继承与抽象产品类,工厂就是创建该类对象

    shanzm_singlefactory_UML



    2. 示例

    示例源于《大话设计模式》,通过一个简单的四则计算器来逐步的重构,最终通过简单工厂实现一个简单的四则计算器。

    首先创建一个简单的控制台项目,实现一个简单的四则运算计算器功能

    当提示用户输入两个数字,并输入一个四则运算符,实现计算功能

    2.1 计算器V1.0

    namespace Calculator
    {
        public class Operation
        {
            public static double GetResult(double numA, double numB, string oper)
            {
                double result = 0;
                switch (oper)
                {
                    case "+":
                        result = numA + numB;
                        break;
                    case "-":
                        result = numA - numB;
                        break;
                    case "*":
                        result = numA * numB;
                        break;
                    case "/":
                        result = numB != 0 ? numA / numB : 0;
                        break;
                }
                return result;
            }
        }
    
         //让业务逻辑和界面逻辑分离
         class Program
        {
            
            static void Main(string[] args)
            {
                try
                {
                    Console.WriteLine("enter a number");
                    double numA = Convert.ToDouble(Console.ReadLine());
    
                    Console.WriteLine("enter another number");
                    double numB = Convert.ToDouble(Console.ReadLine());
    
                    Console.WriteLine("enter operation");
                    string oper = Console.ReadLine();
    
                    Console.WriteLine(Operation.GetResult(numA, numB, oper).ToString());
                    Console.ReadKey();
                }
                catch (Exception e)
                {
    
                    Console.WriteLine("error:" + e.Message);
                    Console.ReadKey();
                }
    
            }
        }
    }
    
    


    2.2 计算器V2.0

    计算器V1.0中使用类对业务逻辑进行封装了

    但是你若是要是想要添加一个新的运算符则要对Operation类进行修改

    其实这样是不安全的,万一你添加新的运算符的时候把原来的运算符的操作代码修改错了

    这样岂不是对项目代码很不安全!

    所以你可以把所有的运算符分别单独定义一个类,这样你就可以随意添加和修改某一个新的运算符

    但是这时候问题又来了,主程序怎么判断要建哪一个运算符的对象
    所以需要一个Factory类来判断建什么对象
    在工厂类中,我们使用里氏原则(子类对象赋值给父类变量)。
    即:先声明一个父类对象的变量,根据用户输入判断新建什么具体的运算符对象

    工厂类,只要有一个静态方法,根据条件的返回一个各种方法的父类对象

    代码示例

    
        //声明Operation基类(使用接口也可以,使用抽象类也可以)
        public abstract class Operation
        {
            private double _numA;
            private double _numB;
    
            public double NumA { get; set; }
            public double NumB { get; set; }
    
    
            public abstract double GetResult()
    
        }
    
        //加法运算符
         public class OperationAdd : Operation
        {
            public override double GetResult()
            {
                double result = 0;
                result = this.NumA + this.NumB;
                return result;
            }
        }
    
        //减法运算符
         public class OperationSub : Operation
        {
            public override double GetResult()
            {
                double result = 0;
                result = this.NumA - this.NumB;
                return result;
            }
        }
    
        //乘法运算符
         public class OperationMul : Operation
        {
            public override double GetResult()
            {
                double result = 0;
                result = this.NumA * this.NumB;
                return result;
            }
        }
    
        //除法运算符
        public class OperationDiv : Operation
        {
            public override double GetResult()
            {
                double result = 0;
                if (this.NumB == 0)
                {
                    throw new Exception("除数不为0!");
                }
                result = this.NumA / this.NumB;
                return result;
            }
        }
    
    
        //工厂类
         public class OperationFactory
        {
            public static Operation CreateOperation(string operation)
            {
                Operation oper = null;
                switch (operation)
                {
                    case "+":
                        oper = new OperationAdd();
                        break;
                    case "-":
                        oper = new OperationSub();
                        break;
                    case "*":
                        oper = new OperationMul();
                        break;
                    case "/":
                        oper = new OperationDiv();
                        break;
                }
                return oper;
            }
        }
    
        //主程序
        class Program
        {
            static void Main(string[] args)
            {
                try
                {
                    Console.WriteLine("enter operation");
                    string operation = Console.ReadLine();
    
                    Operation oper = OperationFactory.CreateOperation(operation);
    
                    Console.WriteLine("enter a number");
                    oper.NumA = Convert.ToDouble(Console.ReadLine());
    
                    Console.WriteLine("enter another number");
                    oper.NumB = Convert.ToDouble(Console.ReadLine());
    
                    double result = oper.GetResult();
                    Console.WriteLine($"运算结果:{result.ToString()}");
                    Console.ReadKey();
    
                }
                catch (Exception e)
                {
    
                    Console.WriteLine("error:" + e.Message);
                    Console.ReadKey();
                }
            }
        }
    

    2.3 程序类图

    shanzm_简单工厂类图



    3. 总结分析

    • 优点:简单工厂模式,使用工厂对象创建具体的产品对象,从而使得对象的使用和创建过程进行的分离。

      客户端不需要关注对象是谁创建的,只要通过工厂中静态方法就可以直接获取其需要的对象

    • 缺点:工厂类中需要选择创建具体某个对象,所以一旦添加新的产品则必须要对工厂中的选择逻辑进行修改,违背了开闭原则!

    • 适应场合:产品类相对较少的情况,使用简单工厂创建产品对象,这样即实现了生产者与消费者的分离,也不会在工厂类中出现太复杂的判断逻辑!



    4. 参考及源码下载

  • 相关阅读:
    git push 出现 you are not allowed to upload merges 错误提示
    构建React-app应用时create-react-app卡住超慢的解决办法<转>
    防抖与节流函数<转>
    this全面解析<转>
    正确的安装和使用nvm(mac)<转>
    TypeScript如何添加自定义d.ts文件(转)
    为什么angular library的build不能将assets静态资源打包进去(转)
    Error: EACCES: permission denied, access '/usr/local/lib/node_modules'
    linux命令新建文件
    mac系统终端sudo免输入密码技能get
  • 原文地址:https://www.cnblogs.com/shanzhiming/p/12616423.html
Copyright © 2011-2022 走看看