翼度科技»论坛 编程开发 .net 查看内容

设计模式-C#实现简单工厂模式

6

主题

6

帖子

18

积分

新手上路

Rank: 1

积分
18
前言

上一篇文章写了如何使用RabbitMQ做个简单的发送邮件项目,然后评论也是比较多,也是准备去学习一下如何确保RabbitMQ的消息可靠性,但是由于时间原因,先来说说设计模式中的简单工厂模式吧!
在了解简单工厂模式之前,我们要知道C#是一款面向对象的高级程序语言。它有3大特性,封装、继承、多态。
简述

工厂模式(Factory Pattern)是一种常用的设计模式,属于创建型模式,它提供了一种创建对象的最佳方式。在工厂模式中,我们创建对象时不会对客户端暴露创建逻辑,并且是通过使用一个共同的接口来指向新创建的对象。
工厂模式的核心是定义一个创建产品对象的工厂接口,将实际创建工作推迟到子类当中。这样客户端可以无需指定具体产品的类,只需通过工厂类即可得到所需的产品对象。
工厂模式主要分为三种类型:简单工厂模式(Simple Factory Pattern)、工厂方法模式(Factory Method Pattern)和抽象工厂模式(Abstract Factory Pattern)。
本文主要讲解简单工厂模式(Simple Factory Pattern)。
案例带入

下面使用C#控制台程序去写一个简易的计算器,实现加减乘除。如果我没学过设计模式,我会这么写:
  1. static void Main(string[] args)  
  2. {  
  3.     Console.WriteLine("请输入数字A:");  
  4.     string A = Console.ReadLine();  
  5.     Console.WriteLine("请选择运算符号:(+、-、*、/):");  
  6.     string op = Console.ReadLine();  
  7.     Console.WriteLine("请输入数字B:");  
  8.     string B = Console.ReadLine();  
  9.     string result = "";  
  10.     switch (op)  
  11.     {        
  12.             case "+":  
  13.             result = Convert.ToString(Convert.ToDouble(A) + Convert.ToDouble(B));  
  14.             break;  
  15.         case "-":  
  16.             result = Convert.ToString(Convert.ToDouble(A) - Convert.ToDouble(B));  
  17.             break;  
  18.         case "*":  
  19.             result = Convert.ToString(Convert.ToDouble(A) * Convert.ToDouble(B));  
  20.             break;  
  21.         case "/":  
  22.             result = Convert.ToString(Convert.ToDouble(A) / Convert.ToDouble(B));  
  23.             break;  
  24.         default:  
  25.             Console.WriteLine("输入的运算符号有误!");  
  26.             break;  
  27.     }   
  28.     Console.WriteLine("结果:" + result);  
  29. }
复制代码
上述代码乍一看没问题,实则隐藏了很多陷阱,比如:

  • 变量命名不规范
  • 除数为0怎么办
  • 输入的不是数字怎么办
  • ......
优化

我们用面向对象的思想进行优化,主要体现在:可维护、可复用、可扩展、灵活性几个方面。通过封装、继承、多态来降低程序的耦合度。
封装

我们可以将运算逻辑封装成一个方法去实现,让主方法减轻负担。封装后:
Operation类
  1. public class Operation
  2. {
  3.     public static double GetResult(double num1, double num2, string op)
  4.     {
  5.         double result = 0d;
  6.         switch (op)
  7.         {
  8.             case "+":
  9.                 result = num1 + num2;
  10.                 break;
  11.             case "-":
  12.                 result = num1 - num2;
  13.                 break;
  14.             case "*":
  15.                 result = num1 * num2;
  16.                 break;
  17.             case "/":
  18.                 result = num1 / num2;
  19.                 break;
  20.         }
  21.         return result;
  22.     }
  23. }
复制代码
Main方法
  1. static void Main(string[] args)
  2. {
  3.         try
  4.         {
  5.                 Console.WriteLine("请输入数字A:");
  6.                 string strNumA = Console.ReadLine();
  7.                 Console.WriteLine("请选择运算符号:(+、-、*、/):");
  8.                 string op = Console.ReadLine();
  9.                 Console.WriteLine("请输入数字B:");
  10.                 string strNumB = Console.ReadLine();
  11.                 string result = "";
  12.                 result = Convert.ToString(Operation.GetResult(Convert.ToDouble(strNumA), Convert.ToDouble(strNumB), op));
  13.                 Console.WriteLine("结果:" + result);
  14.         }
  15.         catch (Exception e)
  16.         {
  17.                 Console.WriteLine("发生异常:" + e.Message);
  18.         }
  19. }
复制代码
松耦合

当我们完成封装后开始思考一个问题,如果后面有新的需求,需要增加一个开根运行,应该如何去修改?如果是我,我会在switch里面加一个分支,但是这样耦合度太高。我明明只需要去开根,但是却要让加减乘除参与进来,所以我们应该将加减乘除运算分离出来。
优化耦合度:
  1. public class Operation
  2. {
  3.     private double _num1;
  4.     private double _num2;
  5.     public double Num1 { get => _num1; set => _num1 = value; }
  6.     public double Num2 { get => _num2; set => _num2 = value; }
  7.     public virtual double GetResult()
  8.     {
  9.         return 0;
  10.     }
  11. }
  12. //加法类
  13. public class AddOperation : Operation
  14. {
  15.     public override double GetResult()
  16.     {
  17.         return Num1 + Num2;
  18.     }
  19. }
  20. //减法类
  21. public class SubtractOperation : Operation
  22. {
  23.     public override double GetResult()
  24.     {
  25.         return Num1 - Num2;
  26.     }
  27. }
  28. //乘法类
  29. public class MultiplyOperation : Operation
  30. {
  31.     public override double GetResult()
  32.     {
  33.         return Num1 * Num2;
  34.     }
  35. }
  36. //除法类
  37. public class DivideOperation : Operation
  38. {
  39.     public override double GetResult()
  40.     {
  41.         if (Num2 == 0)
  42.             throw new DivideByZeroException("除数不能为0");
  43.         return Num1 / Num2;
  44.     }
  45. }  
复制代码
我创建了Operation基类,并定义了2个成员变量_num1和_num2,同时定义了一个GetResult虚方法。同时分别创建了加减乘除子类去重写GetResult方法来降级耦合度。
回归正题(简单工厂模式)

我们需要通过简单工厂模式,来让程序知道该实例化谁。需要来创建一个工厂类:
  1. public class OperationFactory
  2. {
  3.     public static Operation CreateOperation(string operation)
  4.     {
  5.         switch (operation)
  6.         {
  7.             case "+":
  8.                 return new AddOperation();
  9.             case "-":
  10.                 return new SubtractOperation();
  11.             case "*":
  12.                 return new MultiplyOperation();
  13.             case "/":
  14.                 return new DivideOperation();
  15.             default:
  16.                 return null;
  17.         }
  18.     }
  19. }
复制代码
创建了工厂类有什么好处呢,好处就是,只需要输入运算符号,工厂就能自己实例化出合适的对象,通过多态,返回父类的方法实现了计算器的计算结果。
Main方法
通过简单工厂模式,让我们在计算加减乘除的时候只需要去增加对应的子类就行了,下面的代码进行加法运行时,通过传入+号让工厂去帮我们实例化子类。
  1. static void Main(string[] args)  
  2. {  
  3.     try  
  4.     {  
  5.         // 简单工厂模式  
  6.         var oper = OperationFactory.CreateOperation("+");  
  7.         oper.Num1 = 10;  
  8.         oper.Num2 = 5;  
  9.         Console.WriteLine(oper.GetResult());  
  10.     }   
  11.     catch (Exception e)  
  12.     {        
  13.     Console.WriteLine("发生异常:" + e.Message);  
  14.     }
  15. }
复制代码
类图

讲完简单工厂模式后,简简单单复现一下类图:

小小知识点


  • 接口:强调“做什么”,即接口定义了对象应该做什么,而不关心它是如何做的。
  • 虚方法:强调“如何做”,即基类提供了一种实现方式,但允许派生类根据需要进行修改。
参考资料


  • 熟读并反复背诵大话设计模式-程杰出版

来源:https://www.cnblogs.com/ZYPLJ/p/18306505
免责声明:由于采集信息均来自互联网,如果侵犯了您的权益,请联系我们【E-Mail:cb@itdo.tech】 我们会及时删除侵权内容,谢谢合作!

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?立即注册

x

举报 回复 使用道具