设计模式——简单工厂模式
shanzm 人气:0
[TOC]
### 1. 简介 **简单工厂模式(Simple Factory Pattern)**:定义一个工厂类,根据不同的参数,创建并返回不同的类。其中这些类具有一个公共的父类或是一个接口。 简单工厂模式不属于GoF四人组提出的23种设计模式,它是最简单的工厂模式。 简单工厂模式包含类: * **Factory**:工厂类,内部有是个精通的方法,根据参数选择创建的对象 * **Product**:抽象产品类,其作为具体产品的父类,负责定义产品的公共接口 * **ConcreteProduct**:具体产品类,有多个,都是继承与抽象产品类,工厂就是创建该类对象 ![shanzm_singlefactory_UML](https://img2020.cnblogs.com/blog/1576687/202004/1576687-20200401222003109-22673286.png)
### 2. 示例 示例源于《大话设计模式》,通过一个简单的四则计算器来逐步的重构,最终通过简单工厂实现一个简单的四则计算器。 首先创建一个简单的控制台项目,实现一个简单的四则运算计算器功能 当提示用户输入两个数字,并输入一个四则运算符,实现计算功能 #### 2.1 计算器V1.0 ```cs 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`类来判断建什么对象 在工厂类中,我们使用里氏原则(子类对象赋值给父类变量)。 即:先声明一个父类对象的变量,根据用户输入判断新建什么具体的运算符对象 **工厂类,只要有一个静态方法,根据条件的返回一个各种方法的父类对象**。 代码示例 ```cs //声明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_简单工厂类图](https://img2020.cnblogs.com/blog/1576687/202004/1576687-20200401222056280-76974303.png)
### 3. 总结分析 * 优点:简单工厂模式,使用工厂对象创建具体的产品对象,从而使得对象的使用和创建过程进行的分离。 客户端不需要关注对象是谁创建的,只要通过工厂中静态方法就可以直接获取其需要的对象 * 缺点:工厂类中需要选择创建具体某个对象,所以一旦添加新的产品则必须要对工厂中的选择逻辑进行修改,违背了开闭原则! * 适应场合:产品类相对较少的情况,使用简单工厂创建产品对象,这样即实现了生产者与消费者的分离,也不会在工厂类中出现太复杂的判断逻辑!
### 4. 参考及源码下载 [示例源代码下载](https://github.com/shanzm/DesignPatterns) [设计模式——面向对象的设计原则](https://www.cnblogs.com/shanzhiming/p/12608123.html) [《大话设计模式》]()
shanzm-2020年4月1日 22:18:49
### 1. 简介 **简单工厂模式(Simple Factory Pattern)**:定义一个工厂类,根据不同的参数,创建并返回不同的类。其中这些类具有一个公共的父类或是一个接口。 简单工厂模式不属于GoF四人组提出的23种设计模式,它是最简单的工厂模式。 简单工厂模式包含类: * **Factory**:工厂类,内部有是个精通的方法,根据参数选择创建的对象 * **Product**:抽象产品类,其作为具体产品的父类,负责定义产品的公共接口 * **ConcreteProduct**:具体产品类,有多个,都是继承与抽象产品类,工厂就是创建该类对象 ![shanzm_singlefactory_UML](https://img2020.cnblogs.com/blog/1576687/202004/1576687-20200401222003109-22673286.png)
### 2. 示例 示例源于《大话设计模式》,通过一个简单的四则计算器来逐步的重构,最终通过简单工厂实现一个简单的四则计算器。 首先创建一个简单的控制台项目,实现一个简单的四则运算计算器功能 当提示用户输入两个数字,并输入一个四则运算符,实现计算功能 #### 2.1 计算器V1.0 ```cs 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`类来判断建什么对象 在工厂类中,我们使用里氏原则(子类对象赋值给父类变量)。 即:先声明一个父类对象的变量,根据用户输入判断新建什么具体的运算符对象 **工厂类,只要有一个静态方法,根据条件的返回一个各种方法的父类对象**。 代码示例 ```cs //声明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_简单工厂类图](https://img2020.cnblogs.com/blog/1576687/202004/1576687-20200401222056280-76974303.png)
### 3. 总结分析 * 优点:简单工厂模式,使用工厂对象创建具体的产品对象,从而使得对象的使用和创建过程进行的分离。 客户端不需要关注对象是谁创建的,只要通过工厂中静态方法就可以直接获取其需要的对象 * 缺点:工厂类中需要选择创建具体某个对象,所以一旦添加新的产品则必须要对工厂中的选择逻辑进行修改,违背了开闭原则! * 适应场合:产品类相对较少的情况,使用简单工厂创建产品对象,这样即实现了生产者与消费者的分离,也不会在工厂类中出现太复杂的判断逻辑!
### 4. 参考及源码下载 [示例源代码下载](https://github.com/shanzm/DesignPatterns) [设计模式——面向对象的设计原则](https://www.cnblogs.com/shanzhiming/p/12608123.html) [《大话设计模式》]()
加载全部内容