收藏 分销(赏)

敏捷软件开发第五讲-开闭原则与里氏替换原则.ppt

上传人:xrp****65 文档编号:13050245 上传时间:2026-01-11 格式:PPT 页数:34 大小:2.11MB 下载积分:10 金币
下载 相关 举报
敏捷软件开发第五讲-开闭原则与里氏替换原则.ppt_第1页
第1页 / 共34页
敏捷软件开发第五讲-开闭原则与里氏替换原则.ppt_第2页
第2页 / 共34页


点击查看更多>>
资源描述
Page,*,单击此处编辑母版标题样式,单击此处编辑母版文本样式,第二级,第三级,第四级,第五级,HUAWEI TECHNOLOGIES CO.,LTD.,Page,*,单击此处编辑母版标题样式,Huawei Confidential,单击此处编辑母版文本样式,第二级,第三级,第四级,第五级,Thank you,单击此处编辑母版标题样式,单击此处编辑母版文本样式,第二级,第三级,第四级,第五级,单击此处编辑母版标题样式,单击此处编辑母版文本样式,第二级,第三级,第四级,第五级,英文目录标题,:35-40pt,颜色,:R153 G0 B0,内部使用字体,:,FrutigerNext LT Medium,外部使用字体,:Arial,中文目录标题,:35-40pt,颜色,:R153 G0 B0,字体,:,黑体,英文目录正文,:28-30pt,子目录,(2-5,级,):20-30pt,颜色,:,黑色,内部使用字体,:,FrutigerNext LT Regular,外部使用字体,:Arial,中文目录正文,:28-30pt,子目录,(2-5,级,):20-30pt,颜色,:,黑色,字体,:,细黑体,HUAWEI TECHNOLOGIES CO.,LTD.,Huawei Confidential,Security Level:Internal Public,*,HUAWEI TECHNOLOGIES CO.,LTD.,Page,*,单击此处编辑母版标题样式,Huawei Confidential,英文标题,:32-35pt,颜色,:R153 G0 B0,内部使用字体,:,FrutigerNext LT Medium,外部使用字体,:Arial,中文标题,:30-32pt,颜色,:R153 G0 B0,字体,:,黑体,英文正文,:20-22pt,子目录,(2-5,级,):18pt,颜色,:,黑色,内部使用字体,:,FrutigerNext LT Regular,外部使用字体,:Arial,中文正文,:18-20pt,子目录,(2-5,级,):18pt,颜色,:,黑色,字体,:,细黑体,配色参考方案:,建议同一页面内不超过四种颜色,以下是,13,组配色方案,同一页面内只选择一组使用。(仅供参考),客户或者合作伙伴的标志放在右上角,.,单击此处编辑母版文本样式,第二级,第三级,第四级,第五级,Thank you,HUAWEI TECHNOLOGIES CO.,LTD.,Page,*,单击此处编辑母版标题样式,Huawei Confidential,单击此处编辑母版文本样式,第二级,第三级,第四级,第五级,第五讲:开闭原则与里氏,替换原则,目录,开放,封闭原则(,OCP,),OCP,编程实例,OCP,原则实施要点,Liskov,替换原则,Liskov,原则实施要点,总结,开放,封闭原则(,OCP,),什么是软件开发过程中最不稳定的因素?,答案是,需求,!需求在软件开发过程中时时刻刻都可能发生变化。那么,如何灵活应对变化是软件结构设计中最重要也是最困难的一个问题。好的设计带来了极大了灵活性,不好的设计则充斥着僵化的臭味。所以我们要遵循,开放封闭原则,OCP,。,开放,封闭原则(,OCP,),Bertrand Meyer,,面向对象技术大师,发明了,Eiffel,语言和按契约设计(,Design by Contract,)的思想,名著,面向对象软件构造,的作者,法国工程院院士。目前,他除了担任,Eiffel,环境和工具开发公司,ISE,的,CTO,之外,还是爱因斯坦的母校苏黎世联邦工学院计算机科学系教授,担任软件工程项目主席,同时还在澳大利亚,Monash,大学任教。他于,1988,年提出了著名的开放,封闭原则(,OCP,)。,开放封闭原则的现实意义,开放封闭原则(,OCP,,,Open Closed Principle,)是所有面向对象原则的核心。软件设计本身所追求的目标就是,封装变化、降低耦合。,而开放封闭原则正是对这一目标的最直接体现。其他的设计原则,很多时候是为实现这一目标服务的,例如后面将介绍的,Liskov,替换原则实现最佳的、正确的继承层次,就能保证不会违反开放封闭原则。,OCP,核心的思想是:,软件实体应该是可扩展,而不可修改的。也就是说,对扩展是开放的,而对修改是封闭的。,OCP,特征,软件实体(类、模块、函数等)应该是可扩展的,但是不可修改的。,OCP,有两大,特征:,对于扩展是开放的(,Open for extension,),模块的行为可以扩展,当应用的需求改变时,可以对模块进行扩展,以满足新的需求。,对于更改是封闭的(,Closed for modification,),对模块行为扩展时,不必改动模块的源代码或二进制代码。,OCP,的关键在于抽象,OCP,的关键在于抽象,抽象技术:,abstract class,Interface,抽象预见了可能的所有扩展(闭),由抽象可以随时导出新的类(开),范例:手与门,如何在程序中模拟用手去开门和关门?,行为:,开门(,open,),关门(,close,),判断门的状态(,isOpened,),设计实现,public class Door,private boolean _isOpen=false;,public boolean isOpen(),return _isOpen;,public void open(),_isOpen=true;,public void close(),_isOpen=false;,public class Hand,public Door door;,void do(),if(door.isOpen(),door.close();,else,door.open();,public class SmartTest,public static void main(String args),Hand myHand=new Hand();,myHand.door=new Door();,myHand.do();,新的需求,需要手去开关抽屉,冰箱,?,我们只好去修改程序,!,解决新的需求:修改设计,public class Hand,public Door door;,public Drawer drawer;,void do(int item),switch(item),case 1:,if(door.isOpen(),door.close();,else door.open();,break;,case 2:,if(drawer.isOpen(),drawer.close();,else drawer.open();,break;,public class SmartTest,public static void main(String args),Hand myHand=new Hand();,myHand.door=new Door();,myHand.do(1);,手被改了!,主(使用手)程序也被改了!,符合,OCP,的设计方案,public interface Excutable,public boolean isOpen();,public void open();,public void close();,新的实现,public,class Door,implements Excutable,private boolean _isOpen=false;,public boolean isOpen(),return _isOpen;,public void open(),_isOpen=true;,public void close(),_isOpen=false;,public,class Hand,public Excutable item;,void do(),if(item.isOpen(),item.close();,else,item.open();,public,class Drawer,implements Excutable,private boolean _isOpen=false;,public boolean isOpen(),return _isOpen;,public void open(),_isOpen=true;,public void close(),_isOpen=false;,public class SmartTest,public static void main(String args),Hand myHand=new Hand();,myHand.item=new Door();,myHand.do();,新的需求,需要手去开关冰箱,?,为冰箱实现,Excutable,接口,不需要修改任何原有的设计和代码,public,class Refrigerator,implements Excutable,private boolean _isOpen=false;,public boolean isOpen(),return _isOpen;,public void open(),_isOpen=true;,public void close(),_isOpen=false;,OCP,原则实施要点,预测变化和“贴切的”结构,上述的例子其实并不是完全封闭的,如果手增加了新的动作,例如搬运,很多地方还是会有改动变化。那么原来所选定的抽象对于这种变化来说反到成为一种障碍。,一般而言,,无论模块是多么的,“,封闭,”,,都会存在一些无法对之封闭的变化。,没有对于所有的情况都贴切的模型。,设计人员必须对于他们设计的模块应该对哪种变化封闭做出选择。必须先,猜测出最有可能发生的变化种类,然后构造抽象来隔离变化,。,OCP,原则实施要点,要避免进行多余的抽象,遵循,OCP,的代价也是昂贵的。创建正确的抽象是要花费时间和精力的。同时这些抽象也增加了软件的复杂性。因此,开闭原则很难被完全实现,只能在某些模块、某种程度上、某个限度内符合,OCP,的要求。所以可以说,,OCP,具有理想主义的色彩,是,OOD,的终极目标。,在项目很紧张的情况下,一般只会对能,百分之百预测到的变化,经行抽象,而且要是那种会,经常发生变化的部分,才进行抽象。,OCP,原则实施要点,隔离变化的手段,1.,“,只受一次愚弄,”,这意味着在我们最初编写代码时,假设变化不会发生;当变化发生时,我们就创建抽象来隔离以后发生的同类变化。,2.,刺激变化。,我们首先编写测试,我们使用很短的迭代周期进行开发,一个周期为几天而不是几周,我们在加入基础结构之前就开发特性,并且经常性的把那些特性展示给涉众,我们首先开发最重要的特性,尽早的、经常的发布软件,Liskov,替换原则(,LSP,),LSP,(,The Liskov Substitution Principle,Liskov,替换原则),“,若对于类型,S,的任一对象,o,1,,均有类型,T,的对象,o,2,存在,使得在,T,定义的所有程序,P,中,用,o,1,替换,o,2,之后,程序的行为不变,则,S,是,T,的子类型,”,如果在任何情况下,子类(或子类型)或实现类与基类都是可以互换的,那么继承的使用就是合适的。为了达到这一目标,,子类不能添加任何父类没有的附加约束,“,子类对象必须可以替换父类对象,”,从问题开始!,长方形与正方形,假如我们有一个类:长方形(,Rectangle,),我们需要一个新的类,正方形(,Square,),问:可否直接继承长方形?,没问题,因为数学上正方形就是长方形的子类!,开始设计:正方形,public class Rectangle,private int width;,private int height;,public void setWidth(int w),width=w;,public int getWidth(),return width;,public void setHeight(int h),height=h;,public int getHeight(),return height;,public class Square extends Rectangle,public void setWidth(int w),super.setWidth(w);,super.setHeight(w);,public void setHeight(int h),super.setWidth(h);,super.setHeight(h);,设计方案正确吗?,public static void,resize,(Rectangle r),while(r.getHeight()=r.getWidth(),r.setHeight(r.getHeight()+1);,System.out.println(,“,It,s OK.);,Rectangle r1=new Rectangle();,r1.setHeight(5);,r1.setWidth(15);,resize(r1);,Rectangle r2=new Square();,r2.setHeight(5);,r2.setWidth(15);,resize(r2);,使用父类(长方形)时,程序正常运行,使用子类(正方形)时,程序陷入死循环,设计出问题了?继承出问题了?,违背,LSP,原则,Square,类针对,height,、,width,添加了,Rectangle,所没有的附加的约束,违背了,LSP,原则,带来潜在的设计问题(使用,resize,方法时,子类出错!),-,23,-,怎么办?,在可能的情况下,由抽象类(接口)继承,-,24,-,解决方案,IS-A,关系的思考?,鸵鸟是鸟吗?是,鸵鸟有翅膀,鸟也有翅膀,鸵鸟有喙,鸟也有喙,但是,鸟,.getFlySpeed(),鸵鸟,.getRunSpeed(),有着不同,结论:,IS-A,应当是关于行为的。,LSP,清晰的指出,,OOD,中,IS,A,关系是就行为方式而言的,行为方式是可以进行合理假设的,是客户程序所依赖的,。,IS-A,关系的思考,(,续,),对于动物学家,只关心鸟的生理特征,对他们来说,鸵鸟就是鸟,对于养鸟人,关心鸟的行为特征,鸵鸟不是鸟,他们都正确,考虑一个特定设计是否恰当时,不能完全孤立地看这个解决方案,应该根据设计的使用者提出的合理假设来审视。,抽象类与具体类,只要有可能,不要从具体类继承。,行为集中的方向是向上的(抽象类),数据集中的方向是向下的(具体类),LSP,原则实施要点,一个模型,如果孤立的看,并不具有真正意义上的有效性。模型的有效性只能通过它的客户程序来表现。,有谁知道设计的使用者会做出什么样的合理假设呢?大多数这样的假设都很难预测。事实上,如果试图去预测所有这些假设,我们所得到的系统很可能会充满不必要的复杂性的臭味。,因此,像,OCP,原则一样通常最好的办法就是只预测那些,最明显的对于,LSP,的违反情况,,而推迟所有其它的预测,直到出现相关的脆弱性的臭味时,才去处理它们。,LSP,原则实施要点,基于契约设计,基于契约设计(,DBC,:,Design By Contract,)。使用,DBC,,类的编写者能够显式的规定针对该类的契约。客户代码的编写者可以通过该契约获悉可以依赖的行为方式。契约是通过为每个方法声明的前置条件(,preconditions),和后置条件(,postconditions),来指定的。要使一个方法得以执行,前置条件必须要为真。执行完毕后,该方法要保证后置条件为真。,LSP,原则实施要点,在单元测试中指定契约,也可以通过编写单元测试的方式来指定契约。客户代码编写者会去查看这些单元测试,这样他们就可以知道对于要使用的类,应该做什么合理的假设。,LSP,原则实施要点,启发式规则,1.,派生类中的退化函数,在基类中实现了,f(),方法,在派生类中的函数,f(),就是退化的,派生类中的退化函数并不总表示为违反,LSP,,但是当存在这种情况时,还是值得注意一下的。,2.,从派生类中抛出异常,在派生类的方法中添加了其基类不会抛出的异常。如果基类的使用者不期望这些异常,那么把它们添加到派生类的方法中就会导致不可替换性。此时要遵循,LSP,,要么就必须改变使用者的期望,要么派生类就不应该抛出这些异常。,LSP,原则实施要点,里氏替换原则通俗的来讲就是:,子类可以扩展父类的功能,但不能改变父类原有的功能。,下面是几种常用的遵循,LSP,的实施方法:,子类可以实现父类的抽象方法,但不能覆盖父类的非抽象方法。,子类中可以增加自己特有的方法。,当子类的方法重载父类的方法时,方法的前置条件(即方法的形参)要比父类方法的输入参数更宽松。,当子类的方法实现父类的抽象方法时,方法的后置条件(即方法的返回值)要比父类更严格。,总结,在许多方面,,OCP,是面向对象设计的核心所在。遵循这个原则可以带来面向对象技术所声称的巨大好处(也就是:灵活性、可重用性以及可维护性)。然而,并 不是说只要使用一种面向对象语言就是遵循了这个原则。对于应用程序中的每个部分都肆意地进行抽象同样不是一个好主意。正确的做法是,开发人员应该仅仅对程 序中呈现出频繁变化的那些部分做出抽象。拒绝不成熟的抽象和抽象本身一样重要。,总结,LSP,是使,OCP,成为可能的主要原则之一。正是子类型的可替换性才使得使用基类类型的模块在无需修改的情况下就可以扩展。这种可替换性必须使开发人员可以隐式依赖的东西。因此,如果没有显式地强制基类类型的契约,那么代码就必须良好地并且明显地表达出这一点。,俗语,“,IS-A,”,的含义过于宽泛以至于不能作为子类型的定义。子类型的正确定义是,“,可替换性的,”,,这里的可替换性可以通过显式或隐式的契约来定义。,
展开阅读全文

开通  VIP会员、SVIP会员  优惠大
下载10份以上建议开通VIP会员
下载20份以上建议开通SVIP会员


开通VIP      成为共赢上传

当前位置:首页 > 行业资料 > 医学/心理学

移动网页_全站_页脚广告1

关于我们      便捷服务       自信AI       AI导航        抽奖活动

©2010-2026 宁波自信网络信息技术有限公司  版权所有

客服电话:0574-28810668  投诉电话:18658249818

gongan.png浙公网安备33021202000488号   

icp.png浙ICP备2021020529号-1  |  浙B2-20240490  

关注我们 :微信公众号    抖音    微博    LOFTER 

客服