小菜编程成长记(一 面试受挫——代码无错就是好?)第3/3页

 更新时间:2006年10月17日 00:00:00   作者:  

五 体会简单工厂模式的美妙

次日,小菜再来找大鸟,问道:“你昨天说计算器这样的小程序还可以用到面向对象三大特性?继承和多态怎么可能用得上,我实在不可理解。”

大鸟:“小菜很有钻研精神吗?好,今天我让你功力加深一级。你先要考虑一下,你昨天写的这个代码,能否做到很灵活的可修改和扩展呢?”

小菜:“我已经把业务和界面分离了呀,这不是很灵活了吗?”

大鸟:“那我问你,现在如果我希望增加一个开根(sqrt)运算,你如何改?”

小菜:“那只需要改Operation类就行了,在switch中加一个分支就行了。”

大鸟:“问题是你要加一个平方根运算,却需要把加减乘除的运算都得来参与编译,如果你一不小心,把加法运算改成了减法,这不是大大的糟糕。打个比方,如果现在公司要求你为公司的薪资管理系统做维护,原来只有技术人员(月薪),市场销售人员(底薪+提成),经理(年薪+股份)三种运算算法,现在要增加兼职工作人员的(时薪)算法,但按照你昨天的程序写法,公司就必须要把包含有的原三种算法的运算类给你,让你修改,你如果心中小算盘一打,‘TMD,公司给我的工资这么低,我真是郁闷,这会有机会了',于是你除了增加了兼职算法以外,在技术人员(月薪)算法中写了一句 
复制代码 代码如下:

if (员工是小菜)
{
salary = salary * 1.1;
}

那就意味着,你的月薪每月都会增加10%(小心被抓去坐牢),本来是让你加一个功能,却使得原有的运行良好的功能代码产生了变化,这个风险太大了。你明白了吗?”

小菜:“哦,你的意思是,我应该把加减乘除等运算分离,修改其中一个不影响另外的几个,增加运算算法也不影响其它代码,是这样吗?”

大鸟:“自己想去吧,如何用继承和多态,你应该有感觉了。”

小菜:“OK,我马上去写。”
复制代码 代码如下:

/// <summary>
/// 运算类
/// </summary>
class Operation
{
private double _numberA = 0;
private double _numberB = 0;

/// <summary>
/// 数字A
/// </summary>
public double NumberA
{
get{ return _numberA; }
set{ _numberA = value;}
}

/// <summary>
/// 数字B
/// </summary>
public double NumberB
{
get{ return _numberB; }
set{ _numberB = value; }
}

/// <summary>
/// 得到运算结果
/// </summary>
/// <returns></returns>
public virtual double GetResult()
{
double result = 0; 
return result;
}
}

复制代码 代码如下:

/// <summary>
/// 加法类
/// </summary>
class OperationAdd : Operation
{
public override double GetResult()
{
double result = 0; 
result = NumberA + NumberB;
return result;
}
}

/// <summary>
/// 减法类
/// </summary>
class OperationSub : Operation
{
public override double GetResult()
{
double result = 0;
result = NumberA - NumberB;
return result;
}
}

/// <summary>
/// 乘法类
/// </summary>
class OperationMul : Operation
{
public override double GetResult()
{
double result = 0;
result = NumberA * NumberB;
return result;
}
}

/// <summary>
/// 除法类
/// </summary>
class OperationDiv : Operation
{
public override double GetResult()
{
double result = 0;
if (NumberB==0)
throw new Exception("除数不能为0。");
result = NumberA / NumberB;
return result;
}
}

小菜:“大鸟哥,我按照你说的方法写出来了一部分,首先是一个运算类,它有两个Number属性,主要用于计算器的前后数,然后有一个虚方法GetResult(),用于得到结果,然后我把加减乘除都写成了运算类的子类,继承它后,重写了GetResult()方法,这样如果要修改任何一个算法,都不需要提供其它算法的代码了。但问题来了,我如何让计算器知道我是希望用哪一个算法呢?”

大鸟:“写得很不错吗,大大超出我的想象了,你现在的问题其实就是如何去实例化对象的问题,哈,今天心情不错,再教你一招‘简单工厂模式',也就是说,到底要实例化谁,将来会不会增加实例化的对象(比如增加开根运算),这是很容易变化的地方,应该考虑用一个单独的类来做这个创造实例的过程,这就是工厂,来,我们看看这个类如何写。”
复制代码 代码如下:

/// <summary>
/// 运算类工厂
/// </summary>
class OperationFactory
{
public static Operation createOperate(string operate)
{
Operation oper = null;
switch (operate)
{
case "+":
{
oper = new OperationAdd();
break;
}
case "-":
{
oper = new OperationSub();
break;
}
case "*":
{
oper = new OperationMul();
break;
}
case "/":
{
oper = new OperationDiv();
break;
}
}

return oper;
}
}

大鸟:“哈,看到吧,这样子,你只需要输入运算符号,工厂就实例化出合适的对象,通过多态,返回父类的方式实现了计算器的结果。”
复制代码 代码如下:

Operation oper;
oper = OperationFactory.createOperate("+");
oper.NumberA = 1;
oper.NumberB = 2;
double result = oper.GetResult();

大鸟: “哈,界面的实现就是这样的代码,不管你是控制台程序,Windows程序,Web程序,PDA或手机程序,都可以用这段代码来实现计算器的功能,当有一天我们需要更改加法运算,我们只需要改哪里?”

小菜:“改OperationAdd 就可以了。”

大鸟: “那么我们需要增加各种复杂运算,比如平方根,立方根,自然对数,正弦余弦等,如何做?”

小菜:“只要增加相应的运算子类就可以了呀。”

大鸟: “嗯?够了吗?”

小菜:“对了,还需要去修改运算类工厂,在switch中增加分支。”

大鸟: “哈,那才对,那如果要修改界面呢?”

小菜:“那就去改界面呀,关运算什么事呀。”

小菜:“ 回想那天我面试题写的代码,我终于明白我为什么写得不成功了,原来一个小小的计算器也可以写出这么精彩的代码,谢谢大鸟。”

大鸟: “吼吼,记住哦,编程是一门技术,更加是一门艺术,不能只满足于写完代码运行结果正确就完事,时常考虑如何让代码更加简炼,更加容易维护,容易扩展和复用,只有这样才可以是真的提高。写出优雅的代码真的是一种很爽的事情。不过学无止境,其实这才是理解面向对象的开始呢。给你出个作业,做一个商场收银软件,营业员根据客户购买商品单价和数量,向客户收费。”

小菜:“就这个?没问题呀。”

相关文章

  • c# 重载WndProc,实现重写“最小化”的实现方法

    c# 重载WndProc,实现重写“最小化”的实现方法

    在做“亦歌桌面版”的时候,发现当打开歌词状态下,用最小化隐藏窗体到托盘的话(如下code #1),在调出发现歌词缩小了(虽然显现的窗体大小跟刚才一样),从这点看调用该方法其实窗体大小是改变了的(这个过程只是不可视而已)。
    2009-02-02
  • c# 删除所有的空文件夹的小例子

    c# 删除所有的空文件夹的小例子

    c# 删除所有的空文件夹的小例子,需要的朋友可以参考一下
    2013-03-03
  • C#简易图片格式转换器实现方法

    C#简易图片格式转换器实现方法

    这篇文章主要介绍了C#简易图片格式转换器实现方法,涉及C#基于WinForm操作图片的相关技巧,具有一定参考借鉴价值,需要的朋友可以参考下
    2015-11-11
  • C#实现绘制面形图表的方法详解

    C#实现绘制面形图表的方法详解

    这篇文章主要介绍了C#实现绘制面形图表的方法,对于C#初学者很好的掌握C#图形绘制有一定的借鉴价值,需要的朋友可以参考下
    2014-07-07
  • Unity中的静态批处理和动态批处理操作

    Unity中的静态批处理和动态批处理操作

    这篇文章主要介绍了Unity中的静态批处理和动态批处理操作,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧
    2021-04-04
  • C#图像处理之浮雕效果实现方法

    C#图像处理之浮雕效果实现方法

    这篇文章主要介绍了C#图像处理之浮雕效果实现方法,可实现图片转换成浮雕效果的功能,需要的朋友可以参考下
    2015-04-04
  • C#中Stopwatch的使用及说明

    C#中Stopwatch的使用及说明

    这篇文章主要介绍了C#中Stopwatch的使用及说明,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2023-02-02
  • 详解WPF如何显示具有层级关系的数据

    详解WPF如何显示具有层级关系的数据

    这篇文章主要为大家详细介绍了在WPF中如何显示具有层级关系的数据,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起学习一下
    2024-04-04
  • WinForm实现的图片拖拽与缩放功能示例

    WinForm实现的图片拖拽与缩放功能示例

    这篇文章主要介绍了WinForm实现的图片拖拽与缩放功能,结合具体实例形式分析了WinForm鼠标事件响应及图片元素动态操作相关实现技巧,需要的朋友可以参考下
    2017-05-05
  • C# 数组中的 indexOf 方法及使用

    C# 数组中的 indexOf 方法及使用

    这篇文章主要介绍了C# 数组中的 indexOf 方法以及indexof方法的使用讲解,需要的朋友可以参考下
    2018-02-02

最新评论