《大话设计模式》之--第1章 代码无错就是优?----简单工厂模式

来源:互联网 发布:电信网络维护工程师 编辑:程序博客网 时间:2024/04/29 12:12

1 代码无错就是优?----简单工厂模式

1.1面试受挫

       小菜今年计算机专业毕业,学了不少的软件开发方面的东东,也能编个小程,踌躇满志地,一心想要找个好单位。当投递了无数份简历之后,终于收到一个单位的面试通知,小菜欣喜若狂。

       单位出了一道题目:“请用任意一种面向对象语言实现一个计算器控制台程序,要求输入两个数和运算符号,得到结果”。

       小菜一看,这还不简单,三下五除二,10分钟就搞定,写完后感觉没错误就交卷了。单位说一周内等通知,但半个月过去了都还木什么消息,小菜纳闷着呢,便找到了从事软件开发工作七年的表哥大鸟,请教原因,大鸟先让小菜把当时的代码给出来,小菜打开电脑10分钟就搞定,代码如下:

 

 

大鸟看后,哈哈大笑,说道:“小菜啊小菜,你上当鸟,人家单位出题的意思,你完全木有明白那,当然不会再联系你哇!”。

小菜不服气地说:“我的代码有错吗?单位题目不就是让我实现一个计算器吗?我写的哪有问题?”

 

1.2初学者代码毛病

大鸟说:“且先不说出题人的意思,单就你现在的代码,就有很多不足的地方,看你那东东,一看你就是个菜鸟~”。

首先,变量命名很随意,不规范;其次,每个判断分支都需要做,相当于做了三次无用功;最后,如果除数为0了或者输入不是数字,怎么办?

1.3代码规范

小菜:“嘿,你说的挺有道理的嘛,我刚才没在意,马上改给你看。”

 

 

大鸟:“88错,改的挺快的嘛,至少就目前而言,代码实现要计算器是没有问题了,但问题是这样的代码是否合乎出题人的意思呢?”

小菜:“难道你的意思是说用面向对象?”

大鸟:“小菜终于领悟了!”。

1.4面向对象编程

小菜:“我总算明白了,他说用任意一种面向对象语言实现,那意思在于用面向对象的编程方法去实现,但当时我确实没有想到,还用的是面向过程的思维。”

大鸟:“所有编程初学者都会遇到这样的问题,就是碰到问题直觉地用计算机能够理解的逻辑来描述和表达,这实际上是用计算机的方式去思考,比如这个计算器的程序,先要求输入两个数和运算符号,然后根据运算符号判断选择如何运算,得到结果,这本身是完全正确的,但这种过程思维方式使得我们的程序只能满足实现当前的需求,程序不易维护、不易扩展、更不容易利用,从而只是完成了任务而已,根本达不到一个高质量代码的要求。”

1.5活字印刷,面向对象

大鸟:“给你讲个故事,你就理解了。”

大鸟:“话说三国时期,曹操带领百万大军攻打东吴,大军在长江赤壁驻扎,军舰连成一片,眼看就要把东吴给灭掉了,统一天下,曹操大悦,于是大宴宾客,在酒席间,曹操诗性大发,不觉呤道:‘喝酒唱歌,人生真爽’。众人一听:‘丞相好诗哇!’于是忙命一印刷工匠刻版印刷,以便流传天下。”

“但是呢,当样版拿出来给曹操一看,曹操觉得不是很happy,说道:‘喝酒唱歌说的太过俗了,还是改成‘对酒当歌’比较happy!’,于是就命工匠重新刻版,工匠只能连夜刻版,之前的工作统统白费。”

“再拿样版给曹操看,曹操还是觉得不好,说:‘人生真爽太直接,还是改为‘人生几何’比较有意境些’工匠听到后直接崩溃!”

大鸟问:“小菜,你说说,这里面问题出在哪里?”

小菜:“三国时期活字印刷尚未发明,要改字的话,就需要将整个板面全部重新刻制”

大鸟:“说的好!如果有了活字印刷,只需要灵活地改动四个字就可以了,其余的工作都未白做。活字印刷就体现了面向对象的很多好处。”

“第一,要改,只需要改变需要改变的字,此为可维护;第二,这些字并非用完就无用了,完全可以在后来的印刷中重复使用,此为可复用;第三,此诗若加字,只需要另刻字加入即可,这是可扩展;第四字的排列其实可能是竖排,可能是横排,此时只需要将字移动到满足排列需求,此为灵活性好。”

“而在活字印刷术出现之前,上面的四种特性都无法得到满足,要个性,必须重刻;要加字,必须重刻;要重新排列,必须重刻;印完这本书后,此版本就无任何再复用价值。”

小菜:“还真是这样的呢,原来我一直很奇怪,为什么火药、指南针、造纸术都是从无到有,从未知到发现的伟大发明,而活字印刷术则仅仅是从刻版印刷到活字印刷的一次技术性的进步,为何不是评印刷术为四大发明之一呢?原来活字印刷成功是这个原因。”

1.6面向对象的好处

大鸟:“嗯,这下你明白了吧,我以前也不懂,后来做了软件开发几年后,经历了太多的类似曹操这样的客户要改变需求,客观来讲的话,客户的需求并不过人,不就改几个字吗,但面对已经完成的程序代码,却是需要几乎重头来过,这实在是龊。其原因还是在于,我们之前所写的代码,不容易维护、灵活性差、不容易扩展、更谈不上可复用,因此面对需求的变化,只能对程序大动手术。之后,我学习了面向对象的分析设计编程思想,开始考虑通过封装、继承、多态把程序的耦合度降低,传统的印刷术的问题就在于所有的字都刻在同一个版面上,造成了耦合度太高所致,开始用设计模式使得程序更加灵活,容易修改,并且易于复用。体会到了面向对象带来的好处,那种感觉真是happy的很哇!”

小菜:“我现在终于领悟了面试出题目的真正目的在于写出的代码易维护、可扩展、且易于复用,那该怎样做呢?”

1.7复制VS复用

大鸟:“现在,我们需要你再写一个windows的计算器,你现在的代码能不能复用?”

小菜:“那还不简单,把代码直接粘过去不就行了?改动又不是很大,不算麻烦。”

大鸟:“小菜看来就是个小菜,Ctrl+CCtrl+V是非常不好的编程习惯,因为当你的代码中重复到一定程序的时候,维护起来简直是一场灾难。越大的系统,这种方式带来的问题就越严重,编程有一个原则,就是尽可能避免重复。想想你写的哪些代码与控制台无关,而只和计算器有关?”

小菜:“你的意思是分一个类?对哇,就是将计算和显示分开。”

1.8业务的封装

大鸟:“准确地说,就是让业务逻辑与显示逻辑进行剥离,让它们之间的耦合度下降。只有分离,才可以达到容易维护或扩展。”

小菜:“那好,我来试试。”

 

 

小菜:“鸟哥,我写好了,你来看看!”

大鸟:“孺鸟可教也,写的不错,这样就完全把业务和界面分离了。”

小菜心里暗骂:“你丫才是鸟呢。”口中说道:“如果你现在要我写一个Windows应用程序的计算器,我就可以复用这个运算类(Operation)了。”

大鸟:“不单是Windows程序,Web版程序需要运算可以用它,PDA、手机等需要移动系统的软件需要运算也可以用它。”

小菜:“哈,面向对象也不过如此,下回写类似代码就不怕了。”

大鸟:“别急,仅此而已,实在谈不上完全面向对象,你只用了面向对象三大特性中的一个,还有两个没有用呢?”

小菜:“面向对象三大特性不就是封装、继承和多态吗,这里我用到的应该是封装。这还不够吗?我实在看不出,这么小的程序如何用到继承。至于多态,其实我一直也不太了解它到底有什么好处,如何使用它。”

大鸟:“慢慢来嘛,要学的东东实在是太多了,你好好想想该如何应用面向对象的继承和多态。”

1.9紧耦合VS松耦合

第二天,小菜问道:“你说计算器这样的小程序还需要用到面向对象三大特性?继承和多态怎么可能用得上,我实在是不能理解。”

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

小菜:“我已经把业务和显示分离的啦,这不是很灵活了吗?”

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

小菜:“那只需要改Operation类就行了,加个if判断分支即可。”

大鸟:“问题是你要增加一个开根运算,却需要让加减乘除运算都得来参与编译,如果你一不小心把加法运算改成了减法,这岂不是大大的糟糕。打个比方,如果现在公司要求你为公司的薪资管理系统做维护,原来只有技术人员(月薪)、市场销售人员(底薪+提成)、经理(年薪+股份)三种运算方式,现要增加兼职工作人员(时薪)的算法,但按照你昨天的程序写法,公司就必须把包含原有三种算法的运算类给你,让你修改,你心中小算盘一打,‘TMD,公司给我的工资这么低,我真是郁闷啊,这下有机会了’,于是你除了增加了兼职算法外,在技术人员(月薪)算法中写了一句if(员工是小菜) {salary = salary * 1.1;},这就意味着,你的月薪每月都会增加10%,本来就是让你加一个功能,却使得原有的运行良好的功能代码产生了变化,这个风险太大了。你明白不?”

小菜:“原来如此,你的意思是我应该把加减乘除运算分离,修改其中任何一个不足以影响另外几个,增加运算算法也不影响其他代码。”

大鸟:“嗯,你再想想如何用继承和多态,你应该有感觉了。”

小菜:“耶,我马上去写。”

 

Operation运算基类

 

加减乘除类

 

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

1.10简单工厂模式

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

 

简单运算工厂类

客户端类

 

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

小菜:“改OperationAdd即可。”

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

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

大鸟:“嗯?够了吗?”

小菜:“对了,还需要去修改运算基类工厂,增加if条件判断的分支。”

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

小菜:“那就去改界面的代码,跟运算无关嘛。”

大鸟:“我们来看看这几个类的结构图。”

原创粉丝点击