我的课件44面向对象设计原则

上传人:E**** 文档编号:90937116 上传时间:2019-06-20 格式:PPT 页数:49 大小:3.27MB
返回 下载 相关 举报
我的课件44面向对象设计原则_第1页
第1页 / 共49页
我的课件44面向对象设计原则_第2页
第2页 / 共49页
我的课件44面向对象设计原则_第3页
第3页 / 共49页
我的课件44面向对象设计原则_第4页
第4页 / 共49页
我的课件44面向对象设计原则_第5页
第5页 / 共49页
点击查看更多>>
资源描述

《我的课件44面向对象设计原则》由会员分享,可在线阅读,更多相关《我的课件44面向对象设计原则(49页珍藏版)》请在金锄头文库上搜索。

1、计算机学院软件工程系 Email:Xiahui_ Telphone:15829202190 QQ:79003370(不聊天),领域设计 对象设计原则,对象设计原则,单一职责原则 Single Responsibility Principle, SRP 开闭原则 Open/Closed Principle, OCP Liskov替换原则 Liskov Substitution Principle, LSP 依赖倒置原则 Dependency Inversion Principle, DSP 接口分离原则 Interface Segregation Principle, ISP 迪米特原则 Law

2、 of Demeter,LOD,单一职责原则,一个类的功能要单一,只做与它相关的事情。 如果你能够想到多于一个的动机去改变一个类,那么该类就具有多于一个的职责。,例一个通信猫的行为描述 interface Modem public void dial(String pno); /拨号 public void hangup(); /挂断 public void send(char c); /发送数据 public char recv(); /接收数据 是否违反了单一职责原则,单一职责原则,interface DataChannel public void send(char c); public

3、 void recv(); ,interface Connection public void dial(string pno); public void hangup(); ,开闭原则(Open-Close Principle),开闭原则OCP(Open-Close Principle)被称作是OOD的基石,是OOD最重要的原则之一。 -由大师Bertrand Meyer在1988年提出 软件实体在扩展性方面应该是开放的,而在更改性方面应该是封闭的 本质:功能允许扩展,代码不能修改,抽象化 一个或多个抽象类或接口,规定出所有的具体类必须提供的方法的特征作为系统设计的抽象层。这个抽象层预见了所

4、有的可能扩展,因此, 在任何扩展情况下都不会被改变,做到了对修改的关闭。 从抽象层导出一个或多个新的具体类可以改变系统的行为,因此系统的设计对扩展是开放的。 找到类中可能变化的部分,将变化的部分封装成对象,开闭原则的关键,开闭原则优点 1. 通过扩展已有的软件系统,可以提供新的行为,以满足对软件的需求,使变化中的软件系统有一定的适应性和灵活性。 2. 已有的软件模块,特别是最重要的抽象层模块的不能再修改,这就使变化中的软件系统有一定的稳定性和延续性。,开闭原则,开闭原则的实现,1.面向接口的编程 通过接口定义所有的具体类必须提供的方法的特征作为系统设计的抽象层; 通过工厂实现对象的实例化,开闭

5、原则的实现,面向接口编程举例,Interface Runable run(); ,class China run() return “china run”; ,主程序 China person = new China(); person.run();,class English run() return “english run”; ,如果想换成English 怎么办,开闭原则的实现,面向接口编程举例,Interface Runable run(); ,class China run() return “china run”; ,主程序 Runable person = new China()

6、; person.run();,class English run() return “english run”; ,达到目标了没有?,开闭原则的实现,面向接口编程举例,Interface Runable run(); ,class China run() return “china run”; ,主程序 Runable person = Factory.create(); person.run();,class English run() return “english run”; ,Factory.create() 方案一 return new China(); 方案二 if(条件) re

7、turn China(); else return China(); 方案三 读取配置文件中的信息,根据配置文件来实例化不同的对象,Spring!,2.封装变化 封装可能发生变化的部分,将可能的变化作为对象。 发生变化的部分包括:命令、事件、属性、算法和状态等,开闭原则的实现,封装变化举例 如果对象的行为基本不变,作为对象的方法;否则就要考虑是否抽象和封装这些行为。 对于可能存在或不存在的属性,比如体温和血压等。可以构造一个身体状态类,保存存在变化的属性,以将变化产生的影响最小化。,3.组合代替继承 谨慎使用继承,继承使得子类与父类耦合性非常强。一旦父类发生变化,必然导致子类也发生变化。,开闭

8、原则的实现,如果不修改类而仅仅依靠增加子类扩展,尽管似乎满足“开闭”原则,但结果变得非常可笑。 替换这个方案的一种方法是采用对象组合,将人的行为抽象为类,3.组合代替继承 采用对象组合,将人的行为抽象为类。,开闭原则举例,设计有什么问题?,开闭原则举例,一个研究生在软件学院做助教(teaching assistant),同时还在校园餐厅打工做收银员(cashier),也就是说,这个研究生有三种角色:学生,助教和收银员,但在同一时刻只能有一种角色” 根据上面的陈述,哪种设计是最合理的?,开闭原则举例,Liskov替换原则,Liskov替换原则为良好的继承定义了一个规范,一句简单的定义包含了四层含

9、义: 1.子类必须完全实现父类的方法 2.有子类出现的地方父类未必就可以出现 3.覆盖或实现父类的方法时输入参数可以被放大 4.覆盖或实现父类的方法时输出结果可以被缩小,原则 子类可以替换父类出现在父类能出现的任何地方,Liskov替换原则,1.子类必须完全实现父类的方法 以CS中的枪为例,Liskov替换原则,士兵类中定义了一个方法killEnemy,使用枪来杀敌人,具体使用什么枪来杀敌人,调用的时候才知道。,public class Client public static void main(String args) /产生三毛这个士兵 Soldier sanMao = new Sold

10、ier(); sanMao.killEnemy(new Rifle(); ,Liskov替换原则,如果我们有一个玩具手枪,定义如下,Liskov替换原则,把玩具枪传递给三毛用来杀敌,三毛,public class Client public static void main(String args) /产生三毛这个士兵 Soldier sanMao = new Soldier(); sanMao.killEnemy(new ToyGun (); ,三毛开了枪,结果什么也没有发生,被人杀了! 如何解决?,解决方案一 在Soldier类中增加instanceof的判断,如果是玩具枪,就不用来杀敌人

11、。这个方法可以解决问题,但是你要知道,在程序中,每增加一个类,所有与这个父类有关系的类都必须修改,你觉得可行吗?,Liskov替换原则,解决方案二 ToyGun脱离继承,建立一个独立的父类,为了做到代码可以复用,可以与AbastractGun建立关联委托关系 。 在AbstractToy中声明声音、形状都委托给AbstractGun处理,仿真枪嘛,形状和声音都要和真实的枪一样了,然后两个基类下的子类自由延展,互不影响。,玩具枪与真实枪分离的类图,Liskov替换原则,Liskov替换原则,玩具枪也是枪 玩具枪是枪是现实世界人的划分,但是在软件系统中要考虑下面这个问题了:子类是否能够完整地实现父

12、类的业务,否则就会出现像上面的拿枪杀敌人时却发现是把玩具枪的笑话。,到底我们犯了什么错误?,Liskov替换原则,错误再举例 类“鸟”中有个方法fly( ),企鹅自然也继承了这个方法,可是企鹅不能飞阿,于是,我们在企鹅的类中覆盖了fly方法,告诉方法的调用者:企鹅是不会飞的。 这完全符合常理。但是,这违反了LSP,企鹅是鸟的子类,可是企鹅却不能飞! 需要注意的是,此处的“鸟”已经不再是生物学中的鸟了,它是软件中的一个类、 一个抽象。,2.有子类出现的地方父类未必就可以出现。 以CS中的枪为例,Liskov替换原则,G3狙击手类的源码代码 public class Snipper public

13、void killEnemy(G3 g3) /首先看看敌人的情况,别杀死敌人,自己也被人干掉 g3.zoomOut(); /开始射击 g3.shoot(); ,Liskov替换原则,使用父类作为参数 public class Client public static void main(String args) /产生三毛这个狙击手 Snipper sanMao = new Snipper(); /强制将步枪转换成G3 Rifle rifle = new Rifle(); sanMao.killEnemy(G3)rifle); ,Liskov替换原则,运行期抛出java.lang.ClassC

14、astException异常,从里氏替换原则来看,就是有子类出现的地方父类未必就可以出现。,3.覆盖或实现父类的方法时输入参数可以被放大 4.覆盖或实现父类的方法时输出结果可以被缩小 举个例子 先给一个父类,把HashMap转换为Collection集合类型,Liskov替换原则,public class Father public Collection doSomething( HashMap map) System.out.println(“父类被执行.“); return map.values(); ,public class Son extends Father /放大输入参数类型 p

15、ublic Collection doSomething(Map map) System.out.println(“子类被执行.“); return map.values(); ,Liskov替换原则,public class Client public static void invoker() /父类存在的地方,子类就应该能够存在 Father f = new Father(); HashMap map = new HashMap(); f.doSomething(map); public static void main(String args) invoker(); ,3.覆盖或实现父

16、类的方法时输入参数可以被放大 4.覆盖或实现父类的方法时输出结果可以被缩小,代码运行后的结果: 父类被执行.,Liskov替换原则,public class Client public static void invoker() /父类存在的地方,子类就应该能够存在 Son f = new Son(); HashMap map = new HashMap(); f.doSomething(map); public static void main(String args) invoker(); ,按照里氏替换原则,父类出现的地方子类就可以出现,代码运行后的结果: 父类被执行.,Liskov替换原

展开阅读全文
相关资源
相关搜索

当前位置:首页 > 高等教育 > 大学课件

电脑版 |金锄头文库版权所有
经营许可证:蜀ICP备13022795号 | 川公网安备 51140202000112号