与演习的作用一样,当我们认知了“重构”这个词之后,在设计时会时刻警惕法则所提到的各种味道,一旦嗅到一些坏的味道,那么就意味着我们要做一些改变了。
当然,如果你并不知道这个可能神秘的词汇,那么也没关系,下面的情况我想大家都遇到过。
我们有一个读取文件的函数readFile(string filepath),这个函数一直运行的很好。但是突然在某一天,我们要加入“读取特定格式的文件”这个新的功能,但是当我们跟往常一样编写代码的时候却发现,新的功能实现代码中,有许多曾经实现过的。
瞬间,肾上腺激素告诉我们:“不,这是不允许的,因为我很懒,同样的代码休想让我写两遍。”但是,前人关于“CPP会让你的代码极难维护”的经验会让我们的手做出这样的决定:为旧函数增加参数使之适应新的需求。
那么我们把它修改成了readFile(string filepath, EMFileType filetype),嗯,对于新的代码我很满意。但是编译器似乎并不认同我的观点――旧的客户代码并没有调用新的函数,编译出错。也许我们应该马上修改编译器指示的那行红色的代码,不不等等,我们真的要改吗?同样的旧代码可能在很多很多的地方出现,如果我们确实有毅力改掉,那么增加第三个功能的时候还要重复?重复…这两个字可以完全击垮我的意志,算了,还是不要提它的好。我们并没有到悬崖边上。
嗯,我想大家都想到了这个办法,哈哈,对了,就是保留旧的函数框架,但函数体内去调用新的函数,就像这样,当然优秀的编译器还为我们带来了好用的函数重载:
readFile(string filepath)
{
readfile(filepath, ftAll); //ftAll是默认的文件类型
}
这样我们没有见到那个可恶的重复,而编译器也非常满意的完成了任务。
<!----><o:p> </o:p>
到这里故事貌似并没有结束,是的,除了函数,我们在进行OOD的时候,遇到同样的问题也是家常便饭。
我们已经实现了一个书籍的类型Book,包含了标题、页数、定价等的字段,当然还包含了送货信息。老板对这个网上售书系统很满意,当然也归功于这个没有出问题的书籍类。
但是,某一天,问题终于来了,老板要扩展业务,增加一个电子书的销售功能,但是,旧的纸质版书籍类型并没有提供下载、文件大小、文件格式等信息,看来我们要再增加一个类型了,嗯,就叫它电子书类。而就在同时,我们也发现,旧的书籍类型有很多东西都可以拿来用,复用是个多么让人激动的词汇啊。这个时候,我想大家至少会想出两种办法来搞定:
1、 使用泛化。<o:p></o:p>
我们首先想到了泛化,这是个很正常的反映,当然也很简单。
同时创建PaperBook和EBook两个类型来分别代表传统书籍和电子书,把EBook类型不能被复用的成员放到PagerBook类型中,然后再在EBook类型中增加它特有的成员。最后让这两个类型继承自Book这个书籍的基类(由原来的书籍类型转换而来)。见下图:
<!----><v:group coordsize="7200,2310" id="_x0000_s1051" coordorigin="2944,10917" editas="canvas" style="WIDTH: 414pt; HEIGHT: 132.6pt; mso-position-horizontal-relative: char; mso-position-vertical-relative: line"><o:lock v:ext="edit" aspectratio="t"></o:lock><v:shapetype o:spt="75" coordsize="21600,21600" filled="f" stroked="f" id="_x0000_t75" path="m@4@5l@4@11@9@11@9@5xe" o:preferrelative="t"><v:stroke joinstyle="miter"></v:stroke><v:formulas><v:f eqn="if lineDrawn pixelLineWidth 0"></v:f><v:f eqn="sum @0 1 0"></v:f><v:f eqn="sum 0 0 @1"></v:f><v:f eqn="prod @2 1 2"></v:f><v:f eqn="prod @3 21600 pixelWidth"></v:f><v:f eqn="prod @3 21600 pixelHeight"></v:f><v:f eqn="sum @0 0 1"></v:f><v:f eqn="prod @6 1 2"></v:f><v:f eqn="prod @7 21600 pixelWidth"></v:f><v:f eqn="sum @8 21600 0"></v:f><v:f eqn="prod @7 21600 pixelHeight"></v:f><v:f eqn="sum @10 21600 0"></v:f></v:formulas><v:path o:extrusionok="f" o:connecttype="rect" gradientshapeok="t"></v:path><o:lock v:ext="edit" aspectratio="t"></o:lock></v:shapetype><v:shape id="_x0000_s1052" type="#_x0000_t75" o:preferrelative="f" style="LEFT: 2944px; WIDTH: 7200px; POSITION: absolute; TOP: 10917px; HEIGHT: 2310px"><v:fill o:detectmouseclick="t"></v:fill><v:path o:extrusionok="t" o:connecttype="none"></v:path><o:lock text="t" v:ext="edit"></o:lock></v:shape><v:rect id="_x0000_s1053" style="LEFT: 5761px; WIDTH: 1566px; POSITION: absolute; TOP: 10917px; HEIGHT: 408px"><v:textbox>
</v:textbox></v:rect><v:rect id="_x0000_s1054" style="LEFT: 4823px; WIDTH: 1565px; POSITION: absolute; TOP: 12276px; HEIGHT: 407px"><v:textbox>
</v:textbox></v:rect><v:rect id="_x0000_s1055" style="LEFT: 6857px; WIDTH: 1566px; POSITION: absolute; TOP: 12276px; HEIGHT: 407px"><v:textbox>
</v:textbox></v:rect><v:rect fillcolor="silver" id="_x0000_s1056" style="LEFT: 5761px; WIDTH: 1566px; POSITION: absolute; TOP: 11325px; HEIGHT: 271px"></v:rect><v:rect fillcolor="silver" id="_x0000_s1057" style="LEFT: 4822px; WIDTH: 1565px; POSITION: absolute; TOP: 12683px; HEIGHT: 271px"><v:fill src="file:///C:\DOCUME~1\ADMINI~1\LOCALS~1\Temp\msohtml1\01\clip_image001.gif" o:title="宽上对角线" type="pattern"></v:fill></v:rect><v:rect fillcolor="silver" id="_x0000_s1058" style="LEFT: 6857px; WIDTH: 1564px; POSITION: absolute; TOP: 12683px; HEIGHT: 272px"><v:fill src="file:///C:\DOCUME~1\ADMINI~1\LOCALS~1\Temp\msohtml1\01\clip_image001.gif" o:title="宽上对角线" type="pattern"></v:fill></v:rect><v:shapetype o:oned="t" o:spt="32" coordsize="21600,21600" filled="f" id="_x0000_t32" path="m,l21600,21600e"><v:path fillok="f" o:connecttype="none" arrowok="t"></v:path><o:lock shapetype="t" v:ext="edit"></o:lock></v:shapetype><v:shape id="_x0000_s1059" type="#_x0000_t32" o:connectortype="straight" style="LEFT: 5606px; WIDTH: 938px; POSITION: absolute; TOP: 11596px; HEIGHT: 680px; flip: y"><v:stroke endarrowwidth="wide" endarrow="block"></v:stroke></v:shape><v:shape id="_x0000_s1060" type="#_x0000_t32" o:connectortype="straight" style="LEFT: 6544px; WIDTH: 1097px; POSITION: absolute; TOP: 11596px; HEIGHT: 680px; flip: x y"><v:stroke endarrowwidth="wide" endarrow="block"></v:stroke></v:shape><w:wrap type="none"></w:wrap><w:anchorlock></w:anchorlock></v:group>
之后,老板告诉我们,很满意。
2、 使用组合。<o:p></o:p>
当然,我们可能还有另一种方法,也不难。
把书籍类型的所有可复用成员提取出来,建立一个BookBaseInfo的类型,之后新增EBook类型。最后在Book和EBook两个类型中增加一个BookBaseInfo类型的组合成员。
<v:group coordsize="7200,2310" id="_x0000_s1041" coordorigin="2944,10917" editas="canvas" style="WIDTH: 414pt; HEIGHT: 132.6pt; mso-position-horizontal-relative: char; mso-position-vertical-relative: line"><o:lock v:ext="edit" aspectratio="t"></o:lock><v:shape id="_x0000_s1042" type="#_x0000_t75" o:preferrelative="f" style="LEFT: 2944px; WIDTH: 7200px; POSITION: absolute; TOP: 10917px; HEIGHT: 2310px"><v:fill o:detectmouseclick="t"></v:fill><v:path o:extrusionok="t" o:connecttype="none"></v:path><o:lock text="t" v:ext="edit"></o:lock></v:shape><v:rect id="_x0000_s1043" style="LEFT: 5918px; WIDTH: 1565px; POSITION: absolute; TOP: 12412px; HEIGHT: 407px"><v:textbox>
</v:textbox></v:rect><v:rect id="_x0000_s1044" style="LEFT: 4666px; WIDTH: 1564px; POSITION: absolute; TOP: 11053px; HEIGHT: 408px"><v:textbox>
</v:textbox></v:rect><v:rect id="_x0000_s1045" style="LEFT: 7169px; WIDTH: 1566px; POSITION: absolute; TOP: 11053px; HEIGHT: 408px"><v:textbox>
</v:textbox></v:rect><v:rect fillcolor="silver" id="_x0000_s1046" style="LEFT: 5918px; WIDTH: 1565px; POSITION: absolute; TOP: 12819px; HEIGHT: 273px"></v:rect><v:rect fillcolor="silver" id="_x0000_s1047" style="LEFT: 4665px; WIDTH: 1564px; POSITION: absolute; TOP: 11461px; HEIGHT: 270px"><v:fill src="file:///C:\DOCUME~1\ADMINI~1\LOCALS~1\Temp\msohtml1\01\clip_image001.gif" o:title="宽上对角线" type="pattern"></v:fill></v:rect><v:rect fillcolor="silver" id="_x0000_s1048" style="LEFT: 7169px; WIDTH: 1565px; POSITION: absolute; TOP: 11461px; HEIGHT: 271px"><v:fill src="file:///C:\DOCUME~1\ADMINI~1\LOCALS~1\Temp\msohtml1\01\clip_image001.gif" o:title="宽上对角线" type="pattern"></v:fill></v:rect><v:shape id="_x0000_s1049" type="#_x0000_t32" o:connectortype="straight" style="LEFT: 6701px; WIDTH: 1251px; POSITION: absolute; TOP: 11732px; HEIGHT: 680px; flip: x"><v:stroke endarrowlength="long" endarrowwidth="wide" endarrow="diamond"></v:stroke></v:shape><v:shape id="_x0000_s1050" type="#_x0000_t32" o:connectortype="straight" style="LEFT: 5447px; WIDTH: 1254px; POSITION: absolute; TOP: 11731px; HEIGHT: 681px"><v:stroke endarrowlength="long" endarrowwidth="wide" endarrow="diamond"></v:stroke></v:shape><w:wrap type="none"></w:wrap><w:anchorlock></w:anchorlock></v:group>
<o:p> </o:p>
嗯,似乎老板也很满意。
<o:p> </o:p>
故事应该还没有结束,因为导演的烟刚抽一半,那么我们继续吧。
任务完成后应该是总结,对于一个职业病级的程序员来说,摔两次跟头会想到第三、第四次是最基本的技能,那么我们来看上面两种方法的优缺点。
首先是泛化方式。使用泛化,可以方便的使用多态来进行父子转换操作,符合了接口隔离原则。但是似乎除了C++之外,其它语言都不支持多重继承,如果将来这些子类还需要重构其它的成员而产生新的父类,那我们的日子就不大好过了。当然我们想到了接口,接口可以多重继承啊,但是,另一个问题是,接口需要实现类型自己来实现代码,这样又会出现可怕的重复…
然后说说组合方式。使用组合,可以很容易的避免多重继承带来的限制,我们可以任意组合多个类型的成员,但这样做的问题是,我们无法隐藏实现细节,需要把组合的成员暴露给客户代码。
如果说上面的总结只是“完美主义”在作怪,但是,事情似乎来的更快。又是某一天,老板又提出了他的新需求:我们要提供各种书的配套源码下载。这是好事啊(某找不到XX书配套源码的仁兄感激涕零的Or2着…),可对于技术并不是什么让人兴奋的事情――重构再次降临,而且非常幸运,我们遇到了刚刚还在批判的“完美主义”。看来,我们不得不找一个更好的办法了。
既然泛化和组合方式各有优缺点,那我们是不是可以…哈,也许在描述泛化方式的时候你已经想到了(所以我会及时的收笔,免得你不会再往下看了,呵呵):
使用接口和组合方式相结合的方法,当然稍微有些复杂。
定义一个IBookBaseInfo接口,然后定义一个类型BookBaseInfo,之后我们延续上述的组合方式,然后,我们分别在Book和EBook两个类型中实现IBookBaseInfo接口,实现部分来调用组合的BookBaseInfo类型成员。
<v:group coordsize="7200,3533" id="_x0000_s1026" coordorigin="2944,9694" editas="canvas" style="WIDTH: 414pt; HEIGHT: 202.8pt; mso-position-horizontal-relative: char; mso-position-vertical-relative: line"><o:lock v:ext="edit" aspectratio="t"></o:lock><v:rect id="_x0000_s1030" style="LEFT: 7169px; WIDTH: 1566px; POSITION: absolute; TOP: 11053px; HEIGHT: 408px"><v:textbox>
</v:textbox></v:rect>
<v:rect fillcolor="silver" id="_x0000_s1031" style="LEFT: 5918px; WIDTH: 1565px; POSITION: absolute; TOP: 12819px; HEIGHT: 273px"></v:rect><v:rect fillcolor="silver" id="_x0000_s1032" style="LEFT: 4665px; WIDTH: 1564px; POSITION: absolute; TOP: 11461px; HEIGHT: 270px"><v:fill src="file:///C:\DOCUME~1\ADMINI~1\LOCALS~1\Temp\msohtml1\01\clip_image001.gif" o:title="宽上对角线" type="pattern"></v:fill></v:rect><v:rect fillcolor="silver" id="_x0000_s1033" style="LEFT: 7169px; WIDTH: 1565px; POSITION: absolute; TOP: 11461px; HEIGHT: 271px"><v:fill src="file:///C:\DOCUME~1\ADMINI~1\LOCALS~1\Temp\msohtml1\01\clip_image001.gif" o:title="宽上对角线" type="pattern"></v:fill></v:rect><v:shape id="_x0000_s1034" type="#_x0000_t32" o:connectortype="straight" style="LEFT: 6701px; WIDTH: 1251px; POSITION: absolute; TOP: 11732px; HEIGHT: 680px; flip: x"><v:stroke endarrowlength="long" endarrowwidth="wide" endarrow="diamond"></v:stroke></v:shape><v:shapetype o:spt="10" coordsize="21600,21600" id="_x0000_t10" adj="6326" path="m@0,l0@0,0@2@0,21600@1,21600,21600@2,21600@0@1,xe"><v:stroke joinstyle="miter"></v:stroke><v:formulas><v:f eqn="val #0"></v:f><v:f eqn="sum width 0 #0"></v:f><v:f eqn="sum height 0 #0"></v:f><v:f eqn="prod @0 2929 10000"></v:f><v:f eqn="sum width 0 @3"></v:f><v:f eqn="sum height 0 @3"></v:f><v:f eqn="val width"></v:f><v:f eqn="val height"></v:f><v:f eqn="prod width 1 2"></v:f><v:f eqn="prod height 1 2"></v:f></v:formulas><v:path limo="10800,10800" o:connecttype="custom" textboxrect="0,0,21600,21600;2700,2700,18900,18900;5400,5400,16200,16200" gradientshapeok="t" o:connectlocs="@8,0;0,@9;@8,@7;@6,@9"></v:path><v:handles><v:h position="#0,topLeft" switch="" xrange="0,10800"></v:h></v:handles></v:shapetype><v:shape id="_x0000_s1036" type="#_x0000_t10" style="LEFT: 6231px; WIDTH: 156px; POSITION: absolute; TOP: 10509px; HEIGHT: 156px"></v:shape><v:shape id="_x0000_s1037" type="#_x0000_t10" style="LEFT: 7170px; WIDTH: 158px; POSITION: absolute; TOP: 10509px; HEIGHT: 156px"></v:shape><v:shape id="_x0000_s1038" type="#_x0000_t32" o:connectortype="straight" style="LEFT: 5448px; WIDTH: 861px; POSITION: absolute; TOP: 10665px; HEIGHT: 388px; flip: y"><v:stroke dashstyle="dash" endarrow="block"></v:stroke></v:shape><v:shape id="_x0000_s1039" type="#_x0000_t32" o:connectortype="straight" style="LEFT: 7249px; WIDTH: 704px; POSITION: absolute; TOP: 10665px; HEIGHT: 388px; flip: x y"><v:stroke dashstyle="dash" endarrow="block"></v:stroke></v:shape><v:rect id="_x0000_s1040" style="LEFT: 5918px; WIDTH: 1722px; POSITION: absolute; TOP: 9966px; HEIGHT: 407px"><v:textbox>
</v:textbox></v:rect><w:wrap type="none"></w:wrap><w:anchorlock></w:anchorlock></v:group>
这样形成一个代理模式之后,就可以让客户代码专心的使用它所需要的逻辑了。
<o:p> </o:p>
OK,导演的烟屁股开始着火了,我们也圆满完成任务。
分享到:
相关推荐
在微创手术机器人设计中,也可以使用机器学习和深度学习技术来优化机器人的性能和稳定性。 本文还讨论了微创手术机器人在临床应用中的前景和挑战。例如,微创手术机器人可以减少手术创伤、缩短恢复时间和提高手术...
在本篇研究中,我们看到研究者们着力于设计一种更为紧凑型的微创手术机器人系统,这项工作的意义不仅在于技术突破,更在于对于微创手术技术推广的促进作用。 首先,研究团队深入分析了daVinci微创机器人体积庞大的...
在实际医疗应用中,设计这样一个多从操作臂系统的微创手术机器人可以显著提升手术效率和准确性,减少手术风险,同时也对医疗资源的合理分配和利用有着积极的推动作用。对于医生而言,这种新型机器人系统可以提供更加...
文章“用于微创手术机器人力觉反馈的六维力和力矩传感器设计”详细介绍了设计一种微型六维力/力矩传感器,用于RMIS技术中的力反馈环节。 该传感器的设计基于电阻检测原理,通过一种新型直接优化方法来确定传感器的...
为了提升微创手术机器人的控制性能,本研究提出了一种基于短时傅里叶变换(Short-Time Fourier Transform,简称STFT)的运动控制系统设计方案,以此解决手术机器人在运动过程中受信号干扰,导致机器人主从臂控制效果...
1. 微创手术机器人系统:是一种使用机器人技术辅助微创手术的系统,具有切口更小、瘢痕更少、恢复时间更短、复发率降低和创伤小等优势。 2. 主从式微创手术机器人系统:是一种微创手术机器人系统,包括主手和从手两...
在微创手术机器人系统中,主从式机器人系统由于其力反馈和操作精度高等特点而备受关注。主从式微创手术机器人的主要组成部分之一是主手,也就是控制端,其结构设计与运动学分析对于整个系统性能的提高至关重要。 主...
在微创手术机器人系统中,“妙手A”机器人系统具有高精度的运动能力,这是确保手术安全和提高手术成功率的关键因素之一。 精度标定是机器人领域中的一项重要技术,它能够确保机器人系统按照预定的精度执行任务。在...
泌尿微创手术机器人结构设计及其运动学分析.pdf
摘要:本文综述了深度学习在微创手术视频分析中的应用研究,涵盖了微创手术视频分析的意义、难点和相关技术内容,重点介绍深度学习算法的优势,并总结了近年来深度学习在微创手术工具检测与跟踪、微创手术工具存在...
骨科手术机器人在微创脊柱手术中的应用近年来得到了快速的发展,其在提高手术精准度、降低风险以及缩短手术时间等方面展现出了显著优势。本文将详细介绍骨科手术机器人在微创脊柱手术中的应用进展。 首先,脊柱手术...
微创手术机器人技术已经成为现代外科手术中极为重要的一部分,其核心在于提供高精度、高稳定性的手术操作。随着手术机器人技术的不断演进,如何让医生在操作过程中获得及时准确的力反馈,从而提高手术质量和安全性,...
总的来说,介入微创手术头垫作为手术过程中的关键辅助设备,其设计和选择直接影响到手术的成功率和患者的舒适度。随着医疗技术的不断进步,我们可以期待更加先进、人性化的设计出现,进一步提升微创手术的安全性和...
这种技术通过激光束的线性指引,能够在手术过程中提供直观的空间定位,使得医生能更精确地进行微创手术。这种激光定位系统由几个关键部分组成,包括激光驱动器、主控制器、卡环、电源线和DVI数据线。系统在工作时...
微创手术,也称为最小侵入性手术,是指使用较传统开放手术更小的切口或无需切口的手术方式,通常使用腔镜或小切口技术进行操作。微创手术的一大优势在于能够减少术后并发症的发生率及死亡率,改善围手术期患者的临床...
同时,末端微器械的设计采用了无耦合结构,解决了传统设计中器械关节部分与手术钳等部件的联动问题,使器械能够独立于其他部分进行操作,这在提高手术精度的同时也降低了手术过程中的风险。 研究还涉及了柔性臂模块...
描述中的“行业文档-设计装置-一种用于腹部微创手术的直视内窥镜.zip”与标题信息一致,再次强调了文件的核心内容是关于直视内窥镜在腹部微创手术中的应用。"zip"格式提示这是一个压缩包,包含的可能有多个相关文件...
这篇学术论文主要关注的是面向喉部微创手术的经口腔单孔柔性机器人设计。喉部是人体重要的器官,复杂的结构使得手术具有挑战性。传统的喉部微创手术通常依赖支撑喉镜,这种方法存在手术视野受限和操作空间狭小的问题...