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

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

面试受挫

两年前,小菜正在读软件工程专业本科四年级,成绩一般,考研刚结束,即将毕业。大学学了不少软件开发方面的东西,也学着编了些小程序,踌躇满志,一心要找一个好单位。当投递了无数份简历后,终于收到了一个单位的面试通知,小菜欣喜若狂。

到了人家单位,前台小姑娘在电脑上给他出了一份题目,上面写着:

在这里插入图片描述

小菜一看,这个还不简单,三下五除二,10分钟不到,小菜写完了,感觉也没错误。交卷后,单位说一周内等通知吧。于是小菜只得耐心等待。可是半个月过去了,什么消息也没有,小菜很纳闷,我的代码实现了呀,为什么不给我机会呢?

时间:2月26日20点  地点:大鸟房间  人物:小菜、大鸟

在这里插入图片描述

小菜找到从事软件开发工作七年的表哥大鸟,请教原因。大鸟,原名李大辽,29岁,小菜的表哥,云南昆明人,毕业后长期从事软件开发和管理工作,近期到上海发展,暂借住小菜家在宝山的空套房里。小菜以向大鸟学习为由,也从市区父母家搬到了宝山与大鸟同住。

大鸟问了题目和了解了小菜代码的细节以后,哈哈大笑,说道:“小菜呀小菜,你上当了,人家单位出题的意思,你完全都没明白,当然不会再联系你了。”

小菜说:“我的代码有错吗?单位题目不就是要我实现一个计算器的代码吗?我这样写有什么问题?”

在这里插入图片描述

初学者代码毛病

大鸟说:“且先不说出题人的意思,单就你现在的代码,就有很多不足的地方需要改进。”

在这里插入图片描述

代码规范

“哦,说得没错,这个我以前听老师说过,可是从来没有在意过,我马上改,改完再给你看看。”

在这里插入图片描述

大鸟:“吼吼,不错,不错,改得很快嘛?至少就目前代码来说,实现计算器是没有问题了,但这样写出的代码是否符合出题人的意思呢?”

小菜:“你的意思是面向对象?”

大鸟:“哈,小菜非小菜也!”

小菜:“说起来也挺好笑的。我第一次听说面向对象,会以为是……是把脸朝向女朋友,表达……表达一种爱慕的意思。”

大鸟:“晕倒!”

面向对象编程

小菜:“我明白你的意思了。他说用任意一种面向对象语言实现,那意思就是要用面向对象的编程方法去实现,对吗?OK,这个我学过,只不过当时我没想到而已。”

大鸟:“所有编程初学者都会有这样的问题,就是碰到问题就直觉地用计算机能够理解的逻辑来描述和表达待解决的问题及具体的求解过程。这其实是用计算机的方式去思考,比如计算器这个程序,先要求输入两个数和运算符号,然后根据运算符号判断选择如何运算,得到结果,这本身没有错,但这样的思维却使得我们的程序只为满足实现当前的需求,程序不容易维护,不容易扩展,更不容易复用,从而达不到高质量代码的要求。”

小菜:“鸟哥呀,我有点糊涂了,如何才能容易维护,容易扩展,又容易复用呢?能不能具体点?”

活字印刷,面向对象

大鸟:“这样吧,我给你讲个故事。你就明白了。”

“话说三国时期,曹操带领百万大军攻打东吴,大军在长江赤壁驻扎,军船连成一片,眼看就要灭掉东吴,统一天下,曹操大悦,于是大宴众文武,在酒席间,曹操诗性大发,不觉吟道:‘喝酒唱歌,人生真爽。……’。众文武齐呼:'丞相好诗!'于是一臣子速命印刷工匠刻版印刷,以便流传天下。”

在这里插入图片描述

“样张出来给曹操一看,曹操感觉不妥,说道:‘喝与唱,此话过俗,**应改为’对酒当歌’**较好!',于是此臣就命工匠重新来过。工匠眼看连夜刻版之工,彻底白费,心中叫苦不迭。只得照办。”

在这里插入图片描述

“样张再次出来请曹操过目,曹操细细一品,觉得还是不好,说:'人生真爽太过直接,应改问语才够意境,因此应改为’对酒当歌,人生几何?……'当大臣转告工匠之时,工匠晕倒……”

在这里插入图片描述

"小菜你说,这里面的问题出在哪里?"大鸟问道。

小菜说:“是不是因为三国时期活字印刷还未发明,所以要改字的时候,就必须要整个刻板全部重新刻。”

大鸟:“说得好!如果有了活字印刷,则只需更改四个字就可,其余工作都未白做。岂不妙哉。”

在这里插入图片描述

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

在这里插入图片描述

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

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

面向对象的好处

大鸟:"哈,这下你明白了?我以前也不懂,不过做了软件开发几年后,经历了太多的类似曹操这样的客户要改变需求,更改最初想法的事件,才逐渐明白当中的道理。其实客观地说,客户的要求也并不过分,不就是改几个字吗,但面对已完成的程序代码,却是需要几乎重头来过,这实在是令人痛苦不堪。

说白了,原因就是我们原先所写的程序,不容易维护,灵活性差,不容易扩展,更谈不上复用,因此面对需求变化,加班加点,对程序动大手术的那种无奈也就成了非常正常的事了。之后当我学习了面向对象的分析设计编程思想,开始考虑通过封装、继承、多态把程序的耦合度降低,传统印刷术的问题就在于所有的字都刻在同一版面上造成耦合度太高所致,开始用设计模式使得程序更加灵活,容易修改,并且易于复用。体会到面向对象带来的好处,那种感觉应该就如同是一中国酒鬼第一次喝到了茅台,西洋酒鬼第一次喝到了XO一样,怎个爽字可形容呀!"

在这里插入图片描述

"是呀是呀,你说得没错,中国古代的四大发明,另三种应该都是科技的进步,伟大的创造或发现。而唯有活字印刷,实在是思想的成功,面向对象的胜利。"小菜也兴奋起来:“你的意思是,面试公司出题的目的是要我写出容易维护,容易扩展,又容易复用的计算器程序?那该如何做呀?”

复制vs.复用

大鸟:“比如说,我现在要求你再写一个Windows的计算器,你现在的代码能不能复用呢?”

在这里插入图片描述

小菜:“那还不简单,把代码复制过去不就行了吗?改动又不大,不算麻烦。”

大鸟:“小菜看来还是小菜呀,有人说初级程序员的工作就是Ctrl+C和Ctrl+V,这其实是非常不好的编码习惯,因为当你的代码中重复的代码多到一定程度,维护的时候,可能就是一场灾难。越大的系统,这种方式带来的问题越严重,编程有一原则,就是尽可能地去避免重复。想想看,你写的这段代码,有哪些是和控制台无关的,而只是和计算器有关的?”

业务的封装

小菜:“你的意思是分一个类出来?哦,对的,让计算和显示分开。”

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

小菜:"让我来试试看。"Operation运算类:

在这里插入图片描述

客户端Test的代码将如下红色框的部分代码:

在这里插入图片描述

改成了:

在这里插入图片描述

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

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

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

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

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

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

小菜:“面向对象三大特性不就是封装、继承和多态吗?这里我用到的应该是封装吧?”

大鸟:“对!面向对象编程的一个特点叫"封装”:将程序的一些方法和执行步骤隐藏起来,只开放外部接口来访问。打比方说,我们根本不需要知道一辆车的引擎究竟如何工作,其实99%的驾驶员是不了解引擎工作原理的,但

他们只要踩下油门,就可以发送指令让引擎工作。那么对于驾驶员来说,引擎就是被封装好的。"

在这里插入图片描述

小菜:"嗯!我的计算器程序有了封装这还不够吗?我实在看不出,这么

小的程序如何用到继承。至于多态,其实我一直也不太了解它到底有什么好

处,如何使用它。"

大鸟:"慢慢来,要学的东西多着呢,你好好想想该如何应用面向对象的

继承和多态。"

紧耦合vs.松耦合

第二天。

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

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

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

大鸟:“如果我希望增加一个指数运算,比如可以算210=?,你如何改?”

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

在这里插入图片描述

大鸟:"问题是你要加一个平方根运算,却需要让加减乘除的运算都得来参与编译,如果你一不小心,把加法运算改成了减法,这岂不是大大的糟糕。

打个比方,如果现在公司要求你为公司的薪资管理系统做维护,原来只有技术人员(月薪)、市场销售人员(底薪+提成)、经理(年薪+股份)三种运算算法,现在要增加兼职工作人员(时薪)的算法,但按照你昨天的程序写法,公司就必须要把包含原三种算法的运算类代码都给你,让你修改,你如果心中小算盘一打,‘公司给我的工资这么低,我真是郁闷,这下有机会了’,于是你除了增加了兼职算法以外,在技术人员(月薪)算法中写了一句

在这里插入图片描述

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

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

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

小菜:“哦!我明白了,要用继承实现运算类。OK,我马上去写。”

Operation运算类:

在这里插入图片描述

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

简单工厂模式

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

简单运算工厂类:

在这里插入图片描述

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

客户端代码:

在这里插入图片描述

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

小菜:“改Add类就可以了。”

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

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

大鸟:“嗯?够了吗?”

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

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

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

大鸟:“好了,最后,我们来看看这几个类的结构图。”

在这里插入图片描述

如果对你有帮助,就一键三连呗(关注+点赞+收藏),我会持续更新更多干货~~

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

程序猿陌名!

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值