还是那几句话:

学无止境,精益求精

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

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

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

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

请用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. 原生js实现二级联动下拉列表菜单

    二级联动下拉列表菜单的难点在于对后台返回的数据进行解析,不多逼逼,直接上代码 上图是后台返回的数据 实现代码如下: var deviceNotExist = true;//防止数据重复 if(data ...

  2. 你不可不知的Java引用类型之——弱引用

    定义 弱引用是使用WeakReference创建的引用,弱引用也是用来描述非必需对象的,它是比软引用更弱的引用类型.在发生GC时,只要发现弱引用,不管系统堆空间是否足够,都会将对象进行回收. 说明 弱 ...

  3. 12.2、多线程通信:queue

    queue: 什么是队列:是一种特殊的结构,类似于列表.不过就像排队一样,队列中的元素一旦取出,那么就会从队列中删除. 线程之间的通信可以使用队列queue来进行 线程如何使用queue.Queue[ ...

  4. 自己搭建anki同步服务器

    最近帮孩子找学习的软件,发现了anki 不过同步速度太慢,但发现可以自己搭建同步服务器 具体方法见https://github.com/dsnopek/anki-sync-server 我的安装过程如 ...

  5. [HDFS_add_3] HDFS 机架感知

    0. 说明  HDFS 副本存放策略 && 配置机架感知 1. HDFS 的副本存放策略 HDFS 的副本存放策略是将一个副本存放在本地机架节点上,另外两个副本放在不同机架的不同节点上 ...

  6. LNMP下动静分离部署phpmyadmin软件包

    LNMP环境肯定是先要配置好的.可以参考我之前的博客.那我们直接进行配置,我这里使用了三台机器进行动静分离部署,第一台负责nginx反向代理,第二台负责php-fpm应用程序以及mariadb的服务器 ...

  7. .whl文件打开方式 Python

    wheel文件本质上就是zip或者rar,只不过他更加方便python的安装以及使用.在之前的图片中我们只要使用pip install wheel 就可以安装wheel. 在安装了wheel之后我们可 ...

  8. Django Form ModelForm modelfromset

    forms 组件 Form 组件 form表单完成的事情 提供input可以提交数据 对提交的数据进行校验 提供错误提示 定义form组件 from django import forms class ...

  9. ajax json 表格排序,分页,自己定义每页数量

    ajax json 表格排序.分页,自己定义每页数量  点击表头能够排序.依照升序或者降序,另外支持多列排序 设置每页数量 演示   XML/HTML Code <table id='examp ...

  10. [Jsoi2015]染色问题

    题目 看到这个限制条件有点多,我们就一直容斥好了 先容斥颜色,我们枚举至少不用\(i\)种颜色 再容斥列,我们枚举至少不用\(j\)列 最后容斥行,枚举至少不用\(k\)行 容斥系数显然是\((-1) ...