23种设计模式之简单工厂

简单工厂模式描述的是,通过类的继承关系,父类(工厂类)与子类(产品类),调用父类中的方法,实际干活儿的是子类中的方法;封装需求的不确定性,做出通用的编程,下面以常用的计算器为例:

最容易想到的写法是:

 1            Console.WriteLine("请输入操作数1:");
 2             double a = double.Parse(Console.ReadLine());
 3             Console.WriteLine("请输入操作符:");
 4             string opt = Console.ReadLine();
 5             Console.WriteLine("请输入操作数2:");
 6             double b = double.Parse(Console.ReadLine());
 7 
 8             double result = 0;
 9 
10             switch (opt)
11             {
12                 case "+":
13                     result = a + b;
14                     break;
15                 case "-":
16                     result = a - b;
17                     break;
18                 case "*":
19                     result = a * b;
20                     break;
21                 case "/":
22                     if (b == 0)
23                     {
24                         throw new Exception("被除数不能为0");
25                     }
26                     result = a / b;
27                     break;
28             }
29             Console.WriteLine("计算结果是:"+result);

这么写,对于控制台来说基本够用了,但是它有很多的弊病:

1.计算结果是直接输出到控制台,如果要做一个WinForm版呢?(目前只有重新写一遍,不能够重用)

2.这里的case只考虑了基本的四则运算,业务变更后,如果有求平方、求立方、开方等运算呢?(那么只能去改写好的方法,一个项目中只有一处还好说,如果有多处要修改,那就麻烦了,可扩展性太差)
3.这段代码也没有体现面向对象的3大特性:封装、继承、多态。

基于以上的种种弊端,需要修改代码:

首先定义一个父类Operat,在类中不考虑未来是否有四则运算及怎样运算

Operat类
 1 /// <summary>
 2     /// 父类计算方法
 3     /// </summary>
 4     public class Operat
 5     {
 6         public double NumberA { get; set; }
 7         public double NumberB { get; set; }
 8         /// <summary>
 9         /// 构造函数
10         /// </summary>
11         /// <param name="a"></param>
12         /// <param name="b"></param>
13         public Operat(double a,double b)
14         {
15             this.NumberA = a;
16             this.NumberB = b;
17         }
18 
19         public virtual double Oper()
20         {
21             double result = 0;
22             return result;
23         }
24     }

只定义了2个操作数和一个计算方法(虚方法,因为这里不知道未来有几个运算)

再定义一个加法类(OperatAdd)来继承它,并实现父类中的计算方法:

OperatAdd类(加法)
 1  class OperatAdd : Operat
 2     {
 3         //构造函数
 4         public OperatAdd(double a,double b):base(a,b)
 5         {
 6 
 7         }
 8         /// <summary>
 9         /// 子类重写父类的Oper方法(实现)
10         /// </summary>
11         /// <returns></returns>
12         public override double Oper()
13         {
14             double result = 0;
15             result = NumberA + NumberB;
16             return result;
17         }
18     }

依次定义后面的3个类(减、乘、除)

OperatSub类(减法)
 1 class OperatSub : Operat
 2     {
 3         public OperatSub(double a,double b):base(a,b)
 4         {
 5 
 6         }
 7         public override double Oper()
 8         {
 9             double result = 0;
10             result= NumberA - NumberB;
11             return result;
12         }
13     }
OperatMult类(乘法)
 1 class OperatMult:Operat
 2     {
 3         public OperatMult(double a,double b):base(a,b)
 4         {
 5 
 6         }
 7         public override double Oper()
 8         {
 9             double result = 0;
10             result= NumberA * NumberB;
11             return result;
12         }
13     }

OperatVision类(除法)

 1 class OperatVision:Operat
 2     {
 3         public OperatVision(double a,double b):base(a,b)
 4         {
 5 
 6         }
 7         public override double Oper()
 8         {
 9             double result = 0;
10             if (NumberB==0)
11             {
12                 throw new Exception("被除数不能为0");
13             }
14             result = NumberA / NumberB;
15             return result;
16         }
17     }

这时候,应该考虑的问题是,在业务中,怎样调用这4个子类中的运算方法(简单工厂)

定义一个工厂类,由工厂类根据具体业务去调用具体的子类(产品类)

 1 /// <summary>
 2     /// 工厂类
 3     /// </summary>
 4    public class OperatFactory
 5     {
 6         public Operat JiSuan(double a, string opt, double b)
 7         {
 8             Operat opt1 = null;
 9             //封装了异同业务需求的差异
10             switch (opt)
11             {
12                 case "+":
13                     opt1 = new OperatAdd(a, b);     //产品1(加法)
14                     break;
15                 case "-":
16                     opt1 = new OperatSub(a, b);    //产品2(减法)
17                     break;
18                 case "*":
19                     opt1 = new OperatMult(a, b);   //产品3(乘法)
20                     break;
21                 case "/":
22                     opt1 = new OperatVision(a, b);  //产品4(除法)
23                     break;
24             }
25             return opt1;        //返回父类对象
26         }
27     }

给opt赋不同的运算,工厂类就会去调用相应的子类,执行计算方法,new出相应的产品类,因为子类中都只是 return result;没有考虑这个结果具体显示在那个地方(控制台还是winform中的label),就变得相当灵活了,并返回父类对象。

控制台去使用时,调用工厂类中JiSuan()方法返回父类对象,即可:

 1          Console.WriteLine("请输入操作数1:");
 2             double a = double.Parse(Console.ReadLine());
 3             Console.WriteLine("请输入操作符:");
 4             string opt = Console.ReadLine();
 5             Console.WriteLine("请输入操作数2:");
 6             double b = double.Parse(Console.ReadLine());
 7 
 8             OperatFactory factory = new OperatFactory();
 9             Operat opt1 = factory.JiSuan(a, opt, b);
10             Console.WriteLine("计算结果是:{0}", opt1.Oper());
11             Console.ReadKey();

而winform的代码也很类似:

 1             lbResult.Text = "";
 2 
 3             lbResult.ForeColor = Color.Red;
 4             lbResult.Font = new Font("宋体", 12);
 5             double a = double.Parse(txtNumber1.Text.Trim());
 6             string opt = cmbOperat.SelectedItem.ToString();
 7             double b = double.Parse(txtNumber2.Text.Trim());
 8 
 9             OperatFactory factory = new OperatFactory();
10             Operat oper = factory.JiSuan(a, opt, b);
11             lbResult.Text = oper.Oper().ToString();

可以看出上面2段代码的第二段几乎是一样的,代码就足够通用了。

 

 

 

转载于:https://www.cnblogs.com/chens2865/p/3732071.html

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/273740.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

原生JDBC操作数据库流程

1、class.forName()加载数据驱动 2、DriverManager.getConnection()获取数据库连接对象。 3、根据SQL或sql会话对象&#xff0c;有两种方式Statement、PreparedStatement。 4、执行sql处理结果集&#xff0c;如果有参数就设置参数。 5、关闭结果集&#xff0c;关闭会话&#xf…

verilog HDL 编码风格

1、有意义且有效的名字。 2、同一信号在不同层次应该保持一致。 3、添加有意义的后缀&#xff0c;使信号的有效性更加明确。 4、模块输出寄存器化&#xff0c;使得输出的驱动强度和输入延时是可以预测的。 5、使用括号表明优先级。 6、每一个if都应该有一个else。如果esle没有任…

为什么要使用PreparedStatement

(个人理解&#xff1a;执行速度&#xff0c;使用方便&#xff0c;代码的可读性维护性&#xff0c;提高性能&#xff0c;安全性 五个方面考虑) 1、PreparedStatement接口继承Statement&#xff0c;PreparedStatement实例包含了预编译的SQL语句&#xff0c;所以PreparedStatement…

session中存放一个对象,只修改对象的属性,不将修改后的对象存放session,发现session中存放的对象也发生改变!

标题简单描述&#xff1a;先将一个对象放入session&#xff0c;只对对象属性值进行修改&#xff0c;但不将修改后的对象存放session中&#xff0c;发现session中存放的对象属性值也相对应的改变。Person personnew PerSon(); request.getSession().setAttribute("person&q…

利用三层交换机实现VLAN间路由配置

利用三层交换机实现VLAN间路由配置 实验目标&#xff1a; 一、 掌握交换机Tag VLAN的配置&#xff1b; 二、掌握三层交换机基本配置方法&#xff1b; 三、 掌握三层交换机的VLAN路由的配置方法&#xff1b; 四、通过三层交换机实现VLAN见相互通信&#xff1b; 技术原理&#xf…

Maven,在pom.xml配置JDK 9版本。

<build><plugins><!-- 设置JDK 9版本 --><plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-compiler-plugin</artifactId> <configuration> …

【leetcode】Path Sum II

Given a binary tree and a sum, find all root-to-leaf paths where each paths sum equals the given sum. For example:Given the below binary tree and sum 22, 5/ \4 8/ / \11 13 4/ \ / \7 2 5 1 return [[5,4,11,2],[5,8,4,5] ] 下午做了个笔试没睡觉…

easyui、表格中添加操作一列,将操作下设置为修改,点击修改弹出该行对象的编号。

页面中的代码(自己引入easy插件)&#xff1a; <body> <div id"table"></div> </body> <script type"text/javascript"> $(function(){$(#table).datagrid({ url:tt.json, //显示的数据striped:true, …

被LTRIM(RTRIM())害死了,差点

LTRIM(character_expression)去掉前置空格 LTRIM(RTRIM())就是把前置和后置空格都去掉。 character_expression可以是常量、变量或列。character_expression必须属于某个可隐式转换为varchar的数据类型(text、ntext和image除外)。否则&#xff0c;请使用CAST显示转换character_…

Mybatis、使用注解的方式编写用户和角色一对多关系,并使用延迟加载

1、数据库准备 CREATE TABLE role ( ID INT(11) NOT NULL COMMENT 编号,ROLE_NAME VARCHAR(30) DEFAULT NULL COMMENT 角色名称,ROLE_DESC VARCHAR(60) DEFAULT NULL COMMENT 角色描述,PRIMARY KEY (ID) ) ENGINEINNODB DEFAULT CHARSETutf8;INSERT INTO role(ID,ROLE_NAME,…

织梦标签大全

关键描述调用标签&#xff1a; <meta name"keywords" content"{dede:field namekeywords/}"> <meta name"description" content"{dede:field namedescription functionhtml2text(me)/}"> -------------------------------…

spring的注入

1、构造函数注入的是设计到的标签&#xff1a;constructor-arg属性&#xff1a;index:指定参数在构造函数参数列表的索引位置type:指定参数在构造函数中的数据类型name:指定参数在构造函数中的名称上面三个都是找谁 &#xff0c;给谁赋值&#xff0c;下面两个指的是赋什么值 va…

.Net中堆栈和堆的区别

首先堆栈和堆&#xff08;托管堆&#xff09;都在进程的虚拟内存中。&#xff08;在32位处理器上每个进程的虚拟内存为4GB&#xff09; 堆栈stack 1、堆栈中存储值类型 2、堆栈实际上是向下填充&#xff0c;即由高内存地址指向低内存地址填充 3、堆栈的工作方式是先分配内存的变…

spring的IOC注解

1、创建对象的注解 含义&#xff1a;使用注解的形式创建对象&#xff0c;交给Spring容器管理(需要配置在类上) Component:组件 Controller:web层 Service:service层 Repository:Dao层默认&#xff1a;创建对象的唯一标识&#xff0c;当前类名首字母小写value属性&#xff1a;指…

PowerDesigner 逆向工程 从SQL文件转换成PDM 从PDM转成CDM

从SQL文件逆向工程到PDM&#xff1a; ①选择file -> Reverse Engineer - > Database ②在General选项卡中选择MySQL数据库&#xff0c;点击确定。 ③using script file 选择你的sql文件&#xff0c;最后选择确定。 从PDM转成CDM&#xff1a; ①选择工具 -> General CD…

SpringMvc的执行过程

Tomcat启动 1、部署项目到Tomcat中 2、启动Tomcat加载Web.xml 3、初始化DispatcherServlet(执行的是init方法) 4、加载配置文件&#xff0c;创建对象交给Spring容器管理 5、通过处理器映射器解析RequestMappin配置&#xff0c;配置‘请求地址’和‘控制器类’的映射关系 小结&a…

自然语言理解——introduction

1.基本概念&#xff1a; NLP&#xff1a;自然语言处理是研究如何利用计算机技术对语言文本&#xff08;句子、篇章或话语等&#xff09;进行处理和加工的一门学科&#xff0c;研究内容包括对词法、句法、语义和语用等信息的识别、分类、提取、转换和生成等各种处理方法和实现技…

Eclipse中弹出OLE Exception窗口

楼主事故原因&#xff1a;首先打开一个类&#xff0c;然后因为手速太快&#xff0c;在该类的编辑窗口中右键&#xff0c;单击&#xff0c;不要问我点了啥&#xff0c;我也不知。后面发现该类的编辑器没有显示任何内容&#xff0c;但是可以发现代码依然存在只是没有显示。 关闭…

HDOJ-3790-最短路径问题 解题报告

一道最短路问题。普通最短路问题的边只有一种权值&#xff0c;而此题的边要考虑两种权值。因为节点n<1000&#xff0c;所以不能够使用Floyd算法&#xff0c;时间复杂度较高&#xff0c;这里使用Dijkstra算法解决。 中文描述&#xff0c;题意不再赘述。只是要注意每条边都有距…

利用自定命令打开常用软件,小白秒变大神。

不多说&#xff0c;先来个效果&#xff0c;WIINR打开运行&#xff0c;输入qq(小编自定的命令)&#xff0c;就能打开。 实现步骤&#xff1a; 1、找到快捷方式(以腾讯QQ为例) 2、将腾讯QQ快捷方式复制粘贴到C:\Windows,并修改名称 3、测试&#xff0c;winr代开运行&#xff0c;…