




已阅读5页,还剩29页未读, 继续免费阅读
版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
第五讲:开闭原则与里氏 替换原则,目录,开放封闭原则(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的任一对象o1,均有类型T的对象o2存在,使得在T定义的所有程序P中,用o1替换o2之后,程序的行为不变,则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(“Its 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中ISA关系是就行为方式而言的,行为方式是可以进行合理假设的,是客户程序所依赖的。,IS-A关系的思考(续),对于动物学家 只关心鸟的生理特征,对他们来说,鸵鸟就是鸟 对于养鸟人 关心鸟的行为特征,鸵鸟不是鸟 他们都正确 考虑一个特定设计是否恰当时,不能完全孤立地看这个解决方案,应该根据设计的使用者提出的合理假设来审视。,抽象类与具体类,只要有可能,不要从具体类继承。 行为集中的方向是向上的(抽象类) 数据集中的方向是向下的(具体类),LSP原则实施要点,一个模型,如果孤立的看,并不具有真正意义上的有效性。模型的有效性只能通过它的客户程序来表现。 有谁知道设计的使用者会做出什么样的合理假设呢?大多数这样的假设都很难预测。事实上,如果试图去预测所有这些假设,我们所得到的系统很可能会充满不必要的复杂性的臭味。 因此,像OCP原则一样通常最好的办法就是只预测那些最明显的对于LSP的违反情况,而推迟所有其它的预测,直到出现相关的脆弱性的臭味时,才去处理它们。,LSP原则实施要点,基于契约设计 基于契约设计(DBC:Design By Contract)。使用DBC,类的编写者能够显式的规定针对该类的契约。客户代码的编写者可以通过该契约获悉可以依赖的行为方式。契约是通过为每个方法声明的前置条件(preconditions)和后置条件(postconditions)来指定的。要使一个方法得以执行,前置条件必须要为真。执行完毕后,该方法要保证后置条件为真。,LSP原则实施要点,在单元测试中指定契约 也可以通过编写单元测试的方式来指定契约。客户代码编写者会去查看这些单元测试,这样他们就可以知道对于要使用的类,应该做什么合理的假设。,LSP原则实施要点,启发式规则 1.派生类中的退化函数 在基类中实现了f()方法,在派生类中的函数f()就是退化的,派生类中的退化函数并不总表示为违反LSP,但是当存在这种情况时,还是值得注意一下的。 2.从派生类中抛出异常 在派生类的方法中添加了其基类不会抛出的异常。如果基类的使用者不期望这些异常,那么把它们添加到派生类的方法中就会导致不可替换性。此时要遵循LSP
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
最新文档
- 2025年日语能力测试N1级阅读专项试卷:深度阅读与理解
- 齐鲁师范学院《网球(2)》2024-2025学年第一学期期末试卷
- 2025年钎焊技术速成指南与考试题库
- 2025年仓库运营经理面试预测题及经验
- 潍坊科技学院《面点工艺学》2024-2025学年第一学期期末试卷
- 贵阳职业技术学院《计算机仿真语言》2024-2025学年第一学期期末试卷
- 中药粉碎机考核试题(附答案)
- 2025年初中地理特岗教师招聘考试重点解析与模拟题
- 2025年初中体育教师招聘笔试备考热点与预测题解析
- 湖北工业大学工程技术学院《三笔基础二》2024-2025学年第一学期期末试卷
- 跨境监管合作模式-洞察及研究
- (2025)工会知识竞赛题库含参考答案
- 企业员工激励奖励制度完整方案
- 2025医学基础知识试题(附答案)
- 2025年江苏省高考政治试题与参考答案
- 客户项目管理办法
- 西藏建筑业用工合同范本
- 软件项目需求调研报告样例
- 科技公司期权管理办法
- WJ30059-2023军用爆炸品设计安全技术规程
- 医疗器械储存、运输应急预案
评论
0/150
提交评论