敏捷软件开发第五讲开闭原则与里氏替换原则_第1页
敏捷软件开发第五讲开闭原则与里氏替换原则_第2页
敏捷软件开发第五讲开闭原则与里氏替换原则_第3页
敏捷软件开发第五讲开闭原则与里氏替换原则_第4页
敏捷软件开发第五讲开闭原则与里氏替换原则_第5页
已阅读5页,还剩29页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

第五讲:开闭原则与里氏

替换原则敏捷软件开发第五讲开闭原则与里氏替换原则共34页,您现在浏览的是第1页!目录开放——封闭原则(OCP)OCP编程实例OCP原则实施要点Liskov替换原则Liskov原则实施要点总结敏捷软件开发第五讲开闭原则与里氏替换原则共34页,您现在浏览的是第2页!开放——封闭原则(OCP)什么是软件开发过程中最不稳定的因素?——答案是需求!需求在软件开发过程中时时刻刻都可能发生变化。那么,如何灵活应对变化是软件结构设计中最重要也是最困难的一个问题。好的设计带来了极大了灵活性,不好的设计则充斥着僵化的臭味。所以我们要遵循——开放封闭原则OCP。敏捷软件开发第五讲开闭原则与里氏替换原则共34页,您现在浏览的是第3页!开放封闭原则的现实意义开放封闭原则(OCP,OpenClosedPrinciple)是所有面向对象原则的核心。软件设计本身所追求的目标就是封装变化、降低耦合。而开放封闭原则正是对这一目标的最直接体现。其他的设计原则,很多时候是为实现这一目标服务的,例如后面将介绍的Liskov替换原则实现最佳的、正确的继承层次,就能保证不会违反开放封闭原则。OCP核心的思想是:

软件实体应该是可扩展,而不可修改的。也就是说,对扩展是开放的,而对修改是封闭的。敏捷软件开发第五讲开闭原则与里氏替换原则共34页,您现在浏览的是第4页!OCP的关键在于抽象OCP的关键在于抽象抽象技术:abstractclass,Interface抽象预见了可能的所有扩展(闭)由抽象可以随时导出新的类(开)敏捷软件开发第五讲开闭原则与里氏替换原则共34页,您现在浏览的是第5页!设计实现publicclassDoor{privateboolean_isOpen=false;publicbooleanisOpen(){return_isOpen;}publicvoidopen(){_isOpen=true;}publicvoidclose(){_isOpen=false;}}publicclassHand{

publicDoordoor;voiddo(){if(door.isOpen())door.close();elsedoor.open();}}publicclassSmartTest{publicstaticvoidmain(String[]args){HandmyHand=newHand();myHand.door=newDoor();myHand.do();}}敏捷软件开发第五讲开闭原则与里氏替换原则共34页,您现在浏览的是第6页!解决新的需求:修改设计publicclassHand{publicDoordoor;publicDrawerdrawer;

voiddo(intitem){switch(item){case1:if(door.isOpen())door.close();elsedoor.open();break; case2: if(drawer.isOpen())drawer.close();elsedrawer.open();break;}}}publicclassSmartTest{publicstaticvoidmain(String[]args){HandmyHand=newHand();myHand.door=newDoor();

myHand.do(1);}}手被改了!主(使用手)程序也被改了!敏捷软件开发第五讲开闭原则与里氏替换原则共34页,您现在浏览的是第7页!新的实现publicclassDoor

implementsExcutable{privateboolean_isOpen=false;publicbooleanisOpen(){return_isOpen;}publicvoidopen(){_isOpen=true;}publicvoidclose(){_isOpen=false;}}publicclassHand{publicExcutableitem;

voiddo(){if(item.isOpen())item.close();elseitem.open();}}publicclassDrawer

implementsExcutable{privateboolean_isOpen=false;publicbooleanisOpen(){return_isOpen;}publicvoidopen(){_isOpen=true;}publicvoidclose(){_isOpen=false;}}publicclassSmartTest{publicstaticvoidmain(String[]args){HandmyHand=newHand();myHand.item=newDoor();

myHand.do();}}敏捷软件开发第五讲开闭原则与里氏替换原则共34页,您现在浏览的是第8页!OCP原则实施要点预测变化和“贴切的”结构上述的例子其实并不是完全封闭的,如果手增加了新的动作,例如搬运,很多地方还是会有改动变化。那么原来所选定的抽象对于这种变化来说反到成为一种障碍。

一般而言,无论模块是多么的“封闭”,都会存在一些无法对之封闭的变化。没有对于所有的情况都贴切的模型。设计人员必须对于他们设计的模块应该对哪种变化封闭做出选择。必须先猜测出最有可能发生的变化种类,然后构造抽象来隔离变化。敏捷软件开发第五讲开闭原则与里氏替换原则共34页,您现在浏览的是第9页!OCP原则实施要点隔离变化的手段1.“只受一次愚弄”

这意味着在我们最初编写代码时,假设变化不会发生;当变化发生时,我们就创建抽象来隔离以后发生的同类变化。2.刺激变化。我们首先编写测试我们使用很短的迭代周期进行开发——一个周期为几天而不是几周我们在加入基础结构之前就开发特性,并且经常性的把那些特性展示给涉众我们首先开发最重要的特性尽早的、经常的发布软件敏捷软件开发第五讲开闭原则与里氏替换原则共34页,您现在浏览的是第10页!从问题开始!长方形与正方形假如我们有一个类:长方形(Rectangle)我们需要一个新的类,正方形(Square)问:可否直接继承长方形?没问题,因为数学上正方形就是长方形的子类!敏捷软件开发第五讲开闭原则与里氏替换原则共34页,您现在浏览的是第11页!设计方案正确吗?publicstaticvoidresize(Rectangler){while(r.getHeight()<=r.getWidth()){r.setHeight(r.getHeight()+1);}System.out.println(“It’sOK.");}Rectangler1=newRectangle();r1.setHeight(5);r1.setWidth(15);resize(r1);Rectangler2=newSquare();r2.setHeight(5);r2.setWidth(15);resize(r2);使用父类(长方形)时,程序正常运行使用子类(正方形)时,程序陷入死循环设计出问题了?继承出问题了?敏捷软件开发第五讲开闭原则与里氏替换原则共34页,您现在浏览的是第12页!-13-怎么办?在可能的情况下,由抽象类(接口)继承敏捷软件开发第五讲开闭原则与里氏替换原则共34页,您现在浏览的是第13页!IS-A关系的思考?鸵鸟是鸟吗?是鸵鸟有翅膀,鸟也有翅膀鸵鸟有喙,鸟也有喙…但是…鸟.getFlySpeed()鸵鸟.getRunSpeed()有着不同结论:IS-A应当是关于行为的。LSP清晰的指出,OOD中IS-A关系是就行为方式而言的,行为方式是可以进行合理假设的,是客户程序所依赖的。敏捷软件开发第五讲开闭原则与里氏替换原则共34页,您现在浏览的是第14页!抽象类与具体类只要有可能,不要从具体类继承。行为集中的方向是向上的(抽象类)数据集中的方向是向下的(具体类)敏捷软件开发第五讲开闭原则与里氏替换原则共34页,您现在浏览的是第15页!LSP原则实施要点基于契约设计基于契约设计(DBC:DesignByContract)。使用DBC,类的编写者能够显式的规定针对该类的契约。客户代码的编写者可以通过该契约获悉可以依赖的行为方式。契约是通过为每个方法声明的前置条件(preconditions)和后置条件(postconditions)来指定的。要使一个方法得以执行,前置条件必须要为真。执行完毕后,该方法要保证后置条件为真。敏捷软件开发第五讲开闭原则与里氏替换原则共34页,您现在浏览的是第16页!LSP原则实施要点启发式规则1.派生类中的退化函数在基类中实现了f()方法,在派生类中的函数f()就是退化的,派生类中的退化函数并不总表示为违反LSP,但是当存在这种情况时,还是值得注意一下的。2.从派生类中抛出异常在派生类的方法中添加了其基类不会抛出的异常。如果基类的使用者不期望这些异常,那么把它们添加到派生类的方法中就会导致不可替换性。此时要遵循LSP,要么就必须改变使用者的期望,要么派生类就不应该抛出这些异常。敏捷软件开发第五讲开闭原则与里氏替换原则共34页,您现在浏览的是第17页!总结在许多方面,OCP是面向对象设计的核心所在。遵循这个原则可以带来面向对象技术所声称的巨大好处(也就是:灵活性、可重用性以及可维护性)。然而,并不是说只要使用一种面向对象语言就是遵循了这个原则。对于应用程序中的每个部分都肆意地进行抽象同样不是一个好主意。正确的做法是,开发人员应该仅仅对程序中呈现出频繁变化的那些部分做出抽象。拒绝不成熟的抽象和抽象本身一样重要。敏捷软件开发第五讲开闭原则与里氏替换原则共34页,您现在浏览的是第18页!开放——封闭原则(OCP)BertrandMeyer,面向对象技术大师,发明了Eiffel语言和按契约设计(DesignbyContract)的思想,名著《面向对象软件构造》的作者,法国工程院院士。目前,他除了担任Eiffel环境和工具开发公司ISE的CTO之外,还是爱因斯坦的母校苏黎世联邦工学院计算机科学系教授,担任软件工程项目主席,同时还在澳大利亚Monash大学任教。他于1988年提出了著名的开放——封闭原则(OCP)。敏捷软件开发第五讲开闭原则与里氏替换原则共34页,您现在浏览的是第19页!OCP特征

软件实体(类、模块、函数等)应该是可扩展的,但是不可修改的。OCP有两大特征:对于扩展是开放的(Openforextension)模块的行为可以扩展,当应用的需求改变时,可以对模块进行扩展,以满足新的需求。对于更改是封闭的(Closedformodification)对模块行为扩展时,不必改动模块的源代码或二进制代码。敏捷软件开发第五讲开闭原则与里氏替换原则共34页,您现在浏览的是第20页!范例:手与门如何在程序中模拟用手去开门和关门?行为:开门(open)关门(close)判断门的状态(isOpened)敏捷软件开发第五讲开闭原则与里氏替换原则共34页,您现在浏览的是第21页!新的需求……需要手去开关抽屉,冰箱……?我们只好去修改程序!敏捷软件开发第五讲开闭原则与里氏替换原则共34页,您现在浏览的是第22页!符合OCP的设计方案publicinterfaceExcutable{publicbooleanisOpen();publicvoidopen();publicvoidclose();}敏捷软件开发第五讲开闭原则与里氏替换原则共34页,您现在浏览的是第23页!新的需求……需要手去开关冰箱……?为冰箱实现Excutable接口不需要修改任何原有的设计和代码publicclassRefrigerator

implementsExcutable{privateboolean_isOpen=false;publicbooleanisOpen(){return_isOpen;}publicvoidopen(){_isOpen=true;}publicvoidclose(){_isOpen=false;}}敏捷软件开发第五讲开闭原则与里氏替换原则共34页,您现在浏览的是第24页!OCP原则实施要点要避免进行多余的抽象遵循OCP的代价也是昂贵的。创建正确的抽象是要花费时间和精力的。同时这些抽象也增加了软件的复杂性。因此,开闭原则很难被完全实现,只能在某些模块、某种程度上、某个限度内符合OCP的要求。所以可以说,OCP具有理想主义的色彩,是OOD的终极目标。

在项目很紧张的情况下,一般只会对能百分之百预测到的变化经行抽象,而且要是那种会经常发生变化的部分才进行抽象。敏捷软件开发第五讲开闭原则与里氏替换原则共34页,您现在浏览的是第25页!Liskov替换原则(LSP)LSP(TheLiskovSubstitutionPrinciple,Liskov替换原则)“若对于类型S的任一对象o1,均有类型T的对象o2存在,使得在T定义的所有程序P中,用o1替换o2之后,程序的行为不变,则S是T的子类型”如果在任何情况下,子类(或子类型)或实现类与基类都是可以互换的,那么继承的使用就是合适的。为了达到这一目标,子类不能添加任何父类没有的附加约束“子类对象必须可以替换父类对象”敏捷软件开发第五讲开闭原则与里氏替换原则共34页,您现在浏览的是第26页!开始设计:正方形publicclassRectangle{privateintwidth;privateintheight;publicvoidsetWidth(intw){width=w;}publicintgetWidth(){returnwidth;}publicvoidsetHeight(inth){height=h;}publicintgetHeight(){returnheight;}}publicclassSquare

extendsRectangle{publicvoidsetWidth(intw){super.setWidth(w);super.setHeight(w);}publicvoidsetHeight(inth){super.setWidth(h);super.setHeight(h);}}敏捷软件开发第五讲开闭原则与里氏替换原则共34页,您现在浏览的是第27页!违背LSP原则Square类针对height、width添加了Rectangle所没有的附加的约束违背了LSP原则带来潜在的设计问题(使用resize方法时,子类出错!)敏捷软件开发第五讲开闭原则与里氏替换原则共34页,您现在浏览的是第28页!-29-解决方案敏捷软件开发第五讲开闭原则与里氏替换原则共34页,您现在浏览的是第29页!IS-A关系的思考(续)对于动物学家只关心鸟的生理特征,对他们来说,鸵鸟就是鸟对于养鸟人关心鸟的行为特征,鸵鸟不是鸟

他们都正确考虑一个特定设计是否恰当时,不能完全孤立地看这个解决方案,应该根据设计的使用者提出的合理假设来审视。敏捷软件开发第五讲开闭原则与里氏替换原则共34页,您现在浏览的是第30页!LSP原则实施要点一个模型,如果孤立的看,并不

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论