简单工厂模式——选择实现

问题引入

请用C++、Java、C#或VB.NET任意一种面向对象语言实现一个计算器控制台程序,要求输入两个数和运算符号,得到结果。
新手最简单的写法

class Program
{
 static void Main(String[] args)
 {
  Console.Write("请输入数字A:");
  string A=Console.ReadLine();
  Console.Write("请选择运算符号(+,=,-,*,/)");
  string B=Console.ReadLine();
  Console.Write("请输入数字B:");
  string C=Console.ReadLine();
  String D="";
  if(B=="+")
   D=Convert.ToString(Convert.ToDouble(A)+Convert.ToDouble(C));
  if(B=="-")
   D=Convert.ToString(Convert.ToDouble(A)-Convert.ToDouble(C));
  if(B=="*")
   D=Convert.ToString(Convert.ToDouble(A)*Convert.ToDouble(C));
  if(B=="/")
   D=Convert.ToString(Convert.ToDouble(A)/Convert.ToDouble(C));
  Console.WriteLine("结果是:"+D);
  
 }
}

这样写的缺点

  • 变量命名不规范
  • 该判断分支会使计算机做无用功
  • 被除数缺少规范

稍加修改

A改为strNumberA
B改为strOperate
C改为strNumberB
if改为switch结构
除之前加上不等于0的判断

修改后还存在什么问题
编码过于结构化,未能体现面向对象的思想,具体体现在

  • 不易维护(修改任何一个计算细节都会影响整个系统)
  • 不易拓展(拓展时会先破坏这个类)
  • 不易复用

面向对象与结构化编程的优点

  • 可维护
  • 可复用
  • 可拓展
  • 灵活性好

问题思考

面向对象编程的三大特性

学习了面向对象,应考虑如何通过封装、继承、多态把程序的耦合度降低,如何使用设计模式使得程序更加的灵活,容易修改,并且易于复用

复制和复用

编程有一原则,就是用尽可能的办法去避免重复,考虑代码,有哪些是和控制台无关的,而只是和计算器有关的。如何让计算和显示分离,如何让业务逻辑和界面逻辑分离等。

封装时考虑紧耦合与松耦合

上述程序在修改时存在不安全性,当增加一个计算功能组件时,需要将整个类重新编译,修改时可能出错。类内耦合过紧,不利于维护

工厂模式

工厂模式简介

工厂模式专门负责将大量有共同接口的类实例化。工厂模式可以动态决定将哪个类实例化,不必事先知道每次要实例化哪个类。工厂模式有以下几种形态:简单工厂(SimpleFactory)模式、工厂方法模式(FactoryMethod)模式、抽象工厂(AbstractFactory)模式

简单工厂模式

SimpleFactory模式根据提供给它的数据,返回几个有可能类中的一个类的实例。通常它返回的类都有一个公共的父类和公共的方法。
简单工厂模式——选择实现_第1张图片
工厂角色Creator(简单工厂类):工厂类在客户端的直接控制下创建产品对象。
抽象产品角色Product(产品类):定义简单工厂创建的对象的父类或它们共同拥有的接口。可以是一个类、抽象类或接口。
具体产品角色ConcreteProduct(产品衍生类):定义工厂具体加工出来的对象。

简单工厂模式实现计算器

抽象产品角色

 public class Operation
    {
        private double numberA = 0;
        private double numberB = 0;
        public double NumberA
        {
            get { return numberA; }
            set {  numberA=value; }
        }
        public double NumberB
        {
            get { return numberB; }
            set { numberB=value; }
        }
        public virtual double GetResult()
        {
            double result = 0;
            return result;
        }
    }

具体产品-加法类

  public class OperationAdd:Operation
    {
        public override double GetResult()
        {
            double result = 0;
            result = NumberA + NumberB;
            return result;
        }
    }

具体产品-减法类

  public class OperationSub:Operation
    {
        public override double GetResult()
        {
            double result = 0;
            result = NumberA - NumberB;
            return result;
        }
    }

具体产品-乘法类

  public class OperationMul:Operation
    {
        public override double GetResult()
        {
            double result = 0;
            result = NumberA * NumberB;
            return result;
        }
    }

具体产品-加法类

  public 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 createOperation(string 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;
        }
    }

客户端

 public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }
        private void btnj_Click(object sender, EventArgs e)
        {
            string ysf = cbB.Text;
            Operation oper;
            oper = OperationFactory.createOperation(ysf);
            oper.NumberA = Convert.ToDouble(tbA.Text);
            oper.NumberB = Convert.ToDouble(tbB.Text);
            double result = oper.GetResult();
            trt.Text =result.ToString();

        }
        private void button1_Click(object sender, EventArgs e)
        {
            cbB.Text = "";
            tbA.Text = "";
            tbB.Text = "";
            trt.Text = "";
        }
        private void Form1_Load(object sender, EventArgs e)
        {

        }
    }

客户端界面
简单工厂模式——选择实现_第2张图片

典型疑问

上面实例中的简单工厂看起来不就是把客户端里面的“new OperationAdd()”移到了简单工厂里面吗?
答:接口是用来封装隔离具体的实现的,目标就是不要让客户端知道封装体内部的具体实现。简单工厂的位置是位于封装体内的,所以简单工厂知道具体类的实现是没有关系的。对于客户端来说,只是知道了接口和简单工厂。

简单工厂的优点与缺点

优点:

  • 工厂类含有必要的判断逻辑,可以决定在什么时候创建哪一个产品类的实例,客户端可以免除直接创建产品对象的责任,而仅仅“消费”产品。简单工厂模式通过这种做法实现了对责任的分割。
    缺点:

  • 当产品类有复杂的等级结构时,工厂类只有自己,以不变应万变,就是模式的缺点。因为工厂类集中了所有产品创建逻辑,一旦不能正常工作,整个系统都要受到影响。

  • 同时,系统拓展困难,一旦添加新产品就不得不修改工厂逻辑,有可能造成工厂逻辑过于复杂。

  • 另外,简单工厂模式通常使用静态工厂方法,这使得无法由子类继承,造成工厂角色无法形成基于继承的等级结构

简单工厂的本质

选择实现

应用场景

  • 如果想要完全封装隔离具体实现,让外部类只能通过接口来操作封装体,则可以选用简单工厂。让客户端通过工厂来获取相应的接口,而无需关心具体的实现。
  • 如果想要八对外创建对象的职责集中管理和控制,可以选择简单工厂

你可能感兴趣的:(设计模式)