还是那几句话:

学无止境,精益求精

十年河东,十年河西,莫欺少年穷

学历代表你的过去,能力代表你的现在,学习代表你的将来

废话不多说,直接进入正题:

现在给你一道面试题,如下:

请用C++,C#,Java或VB.NET等任意一种面向对象语言实现一个计算机控制台程序,要求输入任意两个数字和一个运算符号,得到结果。

你会怎样设计这道程序呢?下面我列举各个面试人员的答卷并作分析(各位看官:看看有没有和你思路一样的答卷):

面试人员菜鸟一的答卷如下:

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

针对菜鸟一的代码,我们作如下分析:

1、变量/函数命名不规范

2、判断分支意味着加减乘除四个判断都必须做,使计算机做了三次无用的判断

3、运算除法时,如果被除数为零时,会异常

总之:上述方法易读性差,易维护性差,不可重构,不可复用,不可扩展,不灵活。因此菜鸟一未被公司录用。

.

面试人员菜鸟二的答卷如下:

        static void Main(string[] args)
{
Console.Write("请输入数字A:");
string strNumberA = Console.ReadLine(); Console.Write("请输入运算符号:");
string strOperate = Console.ReadLine(); Console.Write("请输入数字B:");
string strNumberB = Console.ReadLine(); double strResult = ; switch (strOperate)
{
case "+": strResult = Convert.ToDouble(strNumberA) + Convert.ToDouble(strNumberB); break;
case "-": strResult = Convert.ToDouble(strNumberA) - Convert.ToDouble(strNumberB); break;
case "*": strResult = Convert.ToDouble(strNumberA) * Convert.ToDouble(strNumberB); break;
case "/": if (strNumberB != "")
{
strResult = Convert.ToDouble(strNumberA) / Convert.ToDouble(strNumberB);
}
else
{
Console.WriteLine("除数不能为零"); Console.ReadKey(); return;
}
break;
}
Console.WriteLine("结果为" + strResult);
Console.ReadKey();
}

针对菜鸟二的答卷,我们作如下分析:

1、变量/函数命名基本规范

2、判断分支只运行一次

3、除法运算判断了被除数不能为零的情况

虽说基本实现了计算器加减乘数的功能

但是:

出题人的意思是利用面向对象语言设计一道计算器程序,菜鸟二的程序看似完美,但是并没有使用面向对象思想,因此:菜鸟二的面试结果亦是未被录取。

呜呜,那么怎么设计这道程序才能打动面试官呢?

现在我们深入分析菜鸟二的答卷

如下:

1、业务与输出没有分离(针对业务的单独封装,降低耦合度)

就如同ASP程序和ASP.NET的对比一样。在ASP程序中,页面的HTML代码和业务逻辑CS代码混在一起,看上去十分不舒服,而且容易出错!而,ASP.NET做了输出与业务的分离,也就是Aspx文件和Aspx.cs文件是分开了的!

OK,根据上述观点分析,我们来构造第三种答卷。

.

面试人员菜鸟三的答卷如下:

计算器操作类:

    public class Operate
{
public static double GetResult(double strNumberA, double strNumberB, string strOperate)
{
double strResult=;
switch (strOperate)
{
case "+": strResult = strNumberA + strNumberB; break;
case "-": strResult = strNumberA - strNumberB; break;
case "*": strResult = strNumberA * strNumberB; break;
case "/": if (strNumberB != )
{
strResult = strNumberA / strNumberB;
}
else
{
Console.WriteLine("除数不能为零"); Console.ReadKey();
}
break;
}
return strResult;
}
}

页面输出程序:

        static void Main(string[] args)
{
Console.Write("请输入数字A:");
string strNumberA = Console.ReadLine(); Console.Write("请输入运算符号:");
string strOperate = Console.ReadLine(); Console.Write("请输入数字B:");
string strNumberB = Console.ReadLine(); double strResult = ; Operate.GetResult(Convert.ToDouble(strNumberA), Convert.ToDouble(strNumberB), strOperate);
Console.WriteLine("结果为" + strResult);
Console.ReadKey();
}

针对菜鸟三我们作如下分析:

1、根据菜鸟三的代码,可以清晰的看出:业务与输出作了分离,也就是说菜鸟三针对业务进行了独立的封装。无论是控制台程序还是Windows应用程序或者是Web应用程序等均可以用这个计算器操作类。

OK,菜鸟三不仅做到了业务的单独封装,同时也满足了代码的复用性

但是,菜鸟三依旧做的不算完美,根据出题人的题目要求:运用C++,C#,Java等面向对象语言设计一道计算器程序。注意:这句话的重点是面向对象,我们都知道面向对象设计有三大特性:封装、继承、多态。

菜鸟三虽然做到了:业务的单独封装代码的复用,但是并没有用到三大特性中的其余两个特性:继承多态

OK,在这里各位看官可能会问,一个小小的计算器程序,为何非得用继承和多态呢?

那么,在此,我们针对菜鸟三的答卷作个深入分析,如下:

1、如果现在要求增加平方根运算、或者增加开根运算,该当如何呢?

也许各位看官会这样回复我:这个简单,只需要在Switch分支中增加对应的分支就可以了。

对,各位看官说的不错。

但是:你增加的这个开根运算需要加减乘除都参与编译,如果在你增加的过程中不小心把加法运算改成了减法运算,那岂不是很糟糕?

在此:举个例子:

现在公司要求你为公司的薪资管理系统做维护,原来只有技术人员(月薪),销售人员(底薪加提成),经理(年薪加股份)三种薪资计算方法。现在需要加入临时工的算法(时薪)。

如果按照菜鸟三的写法,上述三种计算方法放在一个Switch中即可,增加临时工薪资计算方法也仅仅只需要增加一个Switch分支即可。但是贪心的你除了增加了一个临时工薪资计算分支外,还偷偷增加了一个如下的分支:

哈哈哈,下个月你就可以领1.1倍薪资了,可能不到下个月你就在看守所了...多么悲哀的一件事情啊!

那么如何解决或避免上述问题呢?答案:我们将加减乘除这几种运算分别封装即可!

于是就有了菜鸟四的写法(菜鸟四能想到这么多已经不算菜鸟了~_~)如下:

运算操作类:

    /// <summary>
/// 运算基类
/// </summary>
public class Operate
{
public double strNumberA { get; set; }
public double strNumberB { get; set; } public virtual double GetResult()
{
double strResult=;
return strResult;
}
} /// <summary>
/// 加法运算
/// </summary>
public class OperateAdd : Operate
{
public override double GetResult()
{
return strNumberA + strNumberB;
}
} /// <summary>
/// 减法运算
/// </summary>
public class OperateSub : Operate
{
public override double GetResult()
{
return strNumberA - strNumberB;
}
} /// <summary>
/// 乘法运算
/// </summary>
public class OperateMul : Operate
{
public override double GetResult()
{
return strNumberA * strNumberB;
}
} /// <summary>
/// 除法运算
/// </summary>
public class OperateDiv : Operate
{
public override double GetResult()
{
if (strNumberB == )
throw new Exception("被除数不能为零!");
return strNumberA / strNumberB;
}
}

输出代码如下:

        static void Main(string[] args)
{
Console.Write("请输入数字A:");
string strNumberA = Console.ReadLine(); Console.Write("请输入运算符号:");
string strOperate = Console.ReadLine(); Console.Write("请输入数字B:");
string strNumberB = Console.ReadLine(); double strResult = ; switch (strOperate)
{
case "+": OperateAdd Add = new OperateAdd(); Add.strNumberA = Convert.ToDouble(strNumberA); Add.strNumberB = Convert.ToDouble(strNumberB); strResult = Add.GetResult(); break;
case "-": OperateSub Sub = new OperateSub(); Sub.strNumberA = Convert.ToDouble(strNumberA); Sub.strNumberB = Convert.ToDouble(strNumberB); strResult = Sub.GetResult(); break;
case "*": OperateMul Mul = new OperateMul(); Mul.strNumberA = Convert.ToDouble(strNumberA); Mul.strNumberB = Convert.ToDouble(strNumberB); strResult = Mul.GetResult(); break;
case "/": OperateDiv Div = new OperateDiv(); Div.strNumberA = Convert.ToDouble(strNumberA); Div.strNumberB = Convert.ToDouble(strNumberB); strResult = Div.GetResult(); break;
}
Console.WriteLine("结果为:" + strResult);
Console.ReadKey();
}

针对菜鸟四的代码分析如下:

如果需要运算多次,就需要多次重复输出代码的Switch分支,这样做,无疑增加了代码的重复量!虽说菜鸟四的代码非常不错了,但是还是有一定的瑕疵!

简单工厂模式闪亮登场

针对菜鸟四代码改进如下(增加工厂类,根据不同的需求,创建不同的对象):

namespace SJMS
{
public class OperateFactory
{
/// <summary>
/// 工厂类,用于创建相应的对象
/// </summary>
/// <param name="strOperate"></param>
/// <returns></returns>
public static Operate GetOperate(string strOperate)
{
Operate Oper = null;
switch (strOperate)
{
case "+": Oper = new OperateAdd(); break;
case "-": Oper = new OperateSub(); break;
case "*": Oper = new OperateMul(); break;
case "/": Oper = new OperateDiv(); break;
}
return Oper;
}
} /// <summary>
/// 运算基类
/// </summary>
public class Operate
{
public double strNumberA { get; set; }
public double strNumberB { get; set; } public virtual double GetResult()
{
double strResult=;
return strResult;
}
} /// <summary>
/// 加法运算
/// </summary>
public class OperateAdd : Operate
{
public override double GetResult()
{
return strNumberA + strNumberB;
}
} /// <summary>
/// 减法运算
/// </summary>
public class OperateSub : Operate
{
public override double GetResult()
{
return strNumberA - strNumberB;
}
} /// <summary>
/// 乘法运算
/// </summary>
public class OperateMul : Operate
{
public override double GetResult()
{
return strNumberA * strNumberB;
}
} /// <summary>
/// 除法运算
/// </summary>
public class OperateDiv : Operate
{
public override double GetResult()
{
if (strNumberB == )
throw new Exception("被除数不能为零!");
return strNumberA / strNumberB;
}
}
}

输出代码如下:

        static void Main(string[] args)
{
Console.Write("请输入数字A:");
string strNumberA = Console.ReadLine(); Console.Write("请输入运算符号:");
string strOperate = Console.ReadLine(); Console.Write("请输入数字B:");
string strNumberB = Console.ReadLine(); double strResult = ; Operate OperateModel = OperateFactory.GetOperate(strOperate);
OperateModel.strNumberA = Convert.ToDouble(strNumberA);
OperateModel.strNumberB = Convert.ToDouble(strNumberB);
strResult = OperateModel.GetResult();
Console.WriteLine("结果为:" + strResult);
Console.ReadKey();
}

OK,上述代码就是由简单工厂模式实现,所谓简单工厂模式我个人的理解是:根据不同的条件,工厂负责生产不同的对象。

大话设计模式上有一些UML类图,在此不作讲解,直接粘贴图片。

上述运算类图如下:

关于UML类图的解读,请各位看官自行查阅资料!

@陈卧龙的博客

代码无错就是优?简单工厂模式 C#的更多相关文章

  1. .Net简单工厂模式,工厂模式,抽象工厂模式实例

    1.定义   简单工厂模式:是由一个工厂对象决定创建出哪一种产品类的实例.简单工厂模式是工厂模式家族中最简单实用的模式,可以理解为是不同工厂模式的一个特殊实现. 工厂模式:定义一个用于创建对象的接口, ...

  2. Java设计模式学习笔记(二) 简单工厂模式

    前言 本篇是设计模式学习笔记的其中一篇文章,如对其他模式有兴趣,可从该地址查找设计模式学习笔记汇总地址 正文开始... 1. 简介 简单工厂模式不属于GoF23中设计模式之一,但在软件开发中应用也较为 ...

  3. 工厂模式之简单工厂模式,head first设计模式

    简单设计模式比较简单,15分钟的时间,跟着我做,十几分钟学会简单设计模式,开始吧: 1.使用new实例化一个对象时,你肯定知道这种代码缺少弹性,绑定着具体的类会导致代码更加脆弱,简单工厂模式就是针对接 ...

  4. JAVA简单工厂模式(从现实生活角度理解代码原理)

    简单工厂模式(Simple Factory),说他简单是因为我们可以将此模式比作一个简单的民间作坊,他们只有固定的生产线生产固定的产品.也可以称他为静态工厂设计模式,类似于之前提到过静态代理设计模式, ...

  5. 简单工厂模式--java代码实现

    简单工厂模式 工厂,生产产品的场所.比如农夫山泉工厂,生产农夫山泉矿泉水.茶π等饮料.矿泉水和茶π都属于饮料,都具有解渴的功能,但是每种饮料给人的感觉是不一样的.矿泉水和茶π在Java中相当于子类,饮 ...

  6. 设计模式-简单工厂模式(SimpleFactory)

    简单工厂模式又叫静态工厂模式,,通过定义一个类(FruitFactory)来负责创建其他类的实例,被创建的实例通常都具有相同的父类(Fruit). 角色和职责: 1.工厂角色(Factory)-Fru ...

  7. PHP设计模式(一)简单工厂模式 (Simple Factory For PHP)

    最近天气变化无常,身为程序猿的寡人!~终究难耐天气的挑战,病倒了,果然,程序猿还需多保养自己的身体,有句话这么说:一生只有两件事能报复你:不够努力的辜负和过度消耗身体的后患.话不多说,开始吧. 一.什 ...

  8. C#设计模式之简单工厂模式(Simple Factory)

    1. 概述 简单工厂模式就是将一个类的实例化交给一个静态工厂来执行. 2. 使用频率 中 3. 模式结构 3.1 机构图 3.2 模式中的角色 Product:抽象类,把具体产品类公共的代码进行抽象和 ...

  9. 设计模式 — 简单工厂模式(Simple Factory)

    定义:定义一个工厂类,它可以根据参数的不同返回不同类型的实例,被创建的实例通常有公共的父类. 模式类型:创建型模型 Factory(工厂角色):即工厂类,负责实现创建所有产品实例的内部逻辑:工厂类可以 ...

随机推荐

  1. Fiddler 使用fiddler发送捕获的请求及模拟服务器返回

    使用fiddler发送捕获的请求及模拟服务器返回 by:授客 QQ:1033553122 1.做好相关监听及代理设置 略 2.发送捕获的请求 如图 3.模拟服务器返回 本例的一个目的是,根据服务器返回 ...

  2. 测试思想 QA的价值体现

    QA的价值体现 by:授客 QQ:1033553122 1.  缺陷挖掘价值 QA人员一个很重要的价值就是在尽可能短的时间内找出尽可能多的缺陷. 某种意义上说,缺陷直观的反应了产品的质量,QA发现的有 ...

  3. Android深入四大组件(八)广播的注册、发送和接收过程

    前言 我们接着来学习Android四大组件中的BroadcastReceiver,广播主要就是分为注册.接收和发送过程.建议阅读此文前请先阅读Android深入理解四大组件系列的文章,知识重复的部分, ...

  4. loadrunner录制的时候如何应对验证码的问题解决办法?

    对这个问题,我个人的看法是,基本上可以考虑从三个途径来解决该问题: 1.第一种方法,也是最容易想到的,在被测系统中暂时屏蔽验证功能,也就是说,临时修改应用,无论用户输入的是什么验证码,都认为是正确的. ...

  5. Python中识别DataFrame中的nan

    # 识别python中DataFrame中的nanfor i in pfsj.index: if type(pfsj.loc[i]['WZML']) == float: print('float va ...

  6. JMeter 脚本开发(五)

    一.JMeter 元件运行顺序 执行顺序逻辑如下: 1.配置元件(如果存在) 2.前置处理器(如果存在) 3.定时器(如果存在) 4.取样器(如果存在) 5.后置处理器(如果存在且取样器的结果不为空) ...

  7. 总结Hibernate4.1+版本与Hibernate3.3+版本区别

    利用休假时间好好学习了当今流行的ORMapping框架-Hibernate,看完了马士兵老师经典的Hibernate视频教程,也算是小小入门了吧. 马老师在讲课中使用的Hibernate版本是3.3. ...

  8. InnoDB中锁的模式,锁的查看,算法

    InnoDB中锁的模式   Ⅰ.总览 S行级共享锁lock in share mode X行级排它锁增删改 IS意向共享锁 IX意向排他锁 AI自增锁 Ⅱ.锁之间的兼容性 兼 X IX S IS X ...

  9. ELK-elasticsearch-6.3.2插件【head,bigdesk,cerebro[kopf]】安装

    参考博客:linux下ElasticSearch.6.2.2集群安装与head.Kibana.X-Pack..插件的配置安装 参考博客:ELK5.5.1 插件安装实践纪要(head/bigdesk/k ...

  10. javascript闭包—围观大神如何解释闭包

    闭包的概念已经出来很长时间了,网上资源一大把,本着拿来主意的方法来看看. 这一篇文章 学习Javascript闭包(Closure) 是大神阮一峰的博文,作者循序渐进,讲的很透彻.下面一一剖析. 1. ...