面向对象设计原则

上传人:m**** 文档编号:431732962 上传时间:2023-06-04 格式:DOCX 页数:16 大小:95.28KB
返回 下载 相关 举报
面向对象设计原则_第1页
第1页 / 共16页
面向对象设计原则_第2页
第2页 / 共16页
面向对象设计原则_第3页
第3页 / 共16页
面向对象设计原则_第4页
第4页 / 共16页
面向对象设计原则_第5页
第5页 / 共16页
点击查看更多>>
资源描述

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

1、面向对象设计六大原则面向对象设计的原则是面向对象思想的提炼,它比面向对象思想的核心要素更具可操作 性,但与设计模式相比,却又更加的抽象,是设计精神要义的抽象概括。形象地将,面向对 象思想像法理的精神,设计原则则相对于基本宪法,而设计模式就好比各式各样的具体法律 条文了。面向对象设计原则有6个:开放封闭原则,单一职责原则,依赖倒置原则,Liskov替换 原则,迪米特法则和合成/聚合复用原则。单一职责原则 ngle Responsibility Principle SRP)There should never be more than one reason for a class to chang

2、e. 什么意思呢? 所谓单一职责原则就是一个类只负责一个职责,只有一个引起变化的原因。 如果一个类承担的职责过多,就等于把这些职责耦合在一起,一个职责的变化会削弱或抑 制这个类完成其他职责的能力,这个耦合会导致脆弱的设计。软件设计真正要做的许多内容,就是发现职责并把这些职责相互分离;如果能够想到多 于一个动机去改变一个类,那么这个类就具有多于一个职责,就应该考虑类的分离。以调制解调器为例如下图:从上述类图里面我们发现有四个方法Dial(拨通电话),Hangup(挂电话),Receive(收到信 息),Send(发送信息),经过分析不难判断出,实际上Dial(拨通电话)和Hangup(挂电话)是

3、属 于连接的范畴,而Receive(收到信息)和Send(发送信息)是属于数据传送的范畴。这里类包括 两个职责,显然违反了 SRP。这样做有潜在的隐患,如果要改变连接的方式,势必要修改Modem,而修改Modem 类的结果导致凡事依赖Modem类可能都需要修改,这样就需要重新编译和部署,不管数据 传输这部分是否需要修改。因此要重构Modem类,从中抽象出两个接口,一个专门负责连接,另一个专门负责数 据传送。依赖Modem类的元素要做相应的细化,根据职责的不同分别依赖不同的接口。如 下图:这样以来,无论单独修改连接部分还是单独修改数据传送部分,都彼此互不影响。总结单一职责优点:降低类的复杂性,提

4、高可维护性提高可读性。降低需求变化带来的风险。需求变化是不可避免的,如果单一职责做的好,一个接口修 改只对相应的实现类有影响,对其它的接口无影响,这对系统的扩展性和维护性都有很大的 帮助。开放封闭原则(Open-Closed Principle OCP)Software entities(classes,modules,functions etc) should open for extension ,but close for modification.什么意思呢? 所谓开放封闭原则就是软件实体应该对扩展开发,而对修改封闭。开放封闭原则是所有 面向对象原则的核心。软件设计本身所追求的目标就是

5、封装变化,降低耦合,而开放封闭原 则正是对这一目标的最直接体现。开放封闭原则主要体现在两个方面: 对扩展开放,意味着有新的需求或变化时,可以对现有代码进行扩展,以适应新的情况。 对修改封闭,意味着类一旦设计完成,就可以独立其工作,而不要对类尽任何修改。为什么要用到开放封闭原则呢? 软件需求总是变化的,世界上没有一个软件的是不变的,因此对软件设计人员来说,必 须在不需要对原有系统进行修改的情况下,实现灵活的系统扩展。如何做到对扩展开放,对修改封闭呢? 实现开放封闭的核心思想就是对抽象编程,而不对具体编程,因为抽象相对稳定。让类 依赖于固定的抽象,所以对修改就是封闭的;而通过面向对象的继承和多态机

6、制,可以实现 对抽象体的继承,通过覆写其方法来改变固有行为,实现新的扩展方法,所以对于扩展就是开放的。 对于违反这一原则的类,必须通过重构来进行改善。常用于实现的设计模式主要有Template Method 模式和 Strategy 模式。而封装变化,是实现这一原则的重要手段,将经常 变化的状态封装为一个类。以银行业务员为例没有实现OCP的设计:public class BankProcess/存款public void Deposite()/取款public void Withdraw()/转账public void Transfer()public class BankStaffpriva

7、te BankProcess bankpro = new BankProcess();public void BankHandle(Client client)switch (client.Type)/存款case deposite: bankpro.Deposite(); break; /取款case withdraw: bankpro.Withdraw(); break; /转账case transfer: bankpro.Transfer(); break;这种设计显然是存在问题的,目前设计中就只有存款,取款和转账三个功能,将来如果 业务增加了,比如增加申购基金功能,理财功能等,就必须要

8、修改 BankProcess 业务类。我 们分析上述设计就不能发现把不能业务封装在一个类里面,违反单一职责原则,而有新的需 求发生,必须修改现有代码则违反了开放封闭原则。从开放封闭的角度来分析,在银行系统中最可能扩展的就是业务功能的增加或变更。对 业务流程应该作为扩展的部分来实现。当有新的功能时,不需要再对现有业务进行重新梳理 然后再对系统做大的修改。如何才能实现耦合度和灵活性兼得呢?那就是抽象,将业务功能抽象为接口,当业务员依赖于固定的抽象时,对修改就是封闭 的,而通过继承和多态继承,从抽象体中扩展出新的实现,就是对扩展的开放。以下是符合OCP的设计:首先声明一个业务处理接口public i

9、nterface IBankProcessvoid Process();public class DepositProcess : IBankProcesspublic void Process()/办理存款业务Console.WriteLine(Process Deposit);public class WithDrawProcess : IBankProcesspublic void Process()/办理取款业务Console.WriteLine(Process WithDraw);public class TransferProcess : IBankProcesspublic vo

10、id Process()/办理转账业务Console.WriteLine(Process Transfer);public class BankStaffprivate IBankProcess bankpro = null;public void BankHandle(Client client)switch (client.Type)/存款case Deposit:userProc =new DepositUser();break;/转账case Transfer:userProc =new TransferUser();break;/取款case WithDraw:userProc =n

11、ew WithDrawUser(); break;userProc.Process();这样当业务变更时,只需要修改对应的业务实现类就可以,其他不相干的业务就不必修 改。当业务增加,只需要增加业务的实现就可以了。设计建议:开放封闭原则,是最为重要的设计原则,Liskov替换原则和合成/聚合复用原则为开放 封闭原则提供保证。可以通过Template Method模式和Strategy模式进行重构,实现对修改封闭,对扩展开 放的设计思路。封装变化,是实现开放封闭原则的重要手段,对于经常发生变化的状态,一般将其封装 为一个抽象,例如银行业务中IBankProcess接口。拒绝滥用抽象,只将经常变化的

12、部分进行抽象。里氏替换原则(Liskov Substitution Principle LSP)里氏替换原则是面向对象设计的基本原则之一。任何基类可以出现的地方,子类一定可 以出现。 LSP 是继承复用的基石,只有当子类可以替换基类,软件单位的功能不受影响时 基类才能真正的被复用,而子类也可以在基类的基础上增加新的行为。Liskov 提出了关于继承的原则:Inheritance should ensure that any property proved about supertype objects also holds for subtype objects. 继承必须确保超类中所拥有的性

13、质在子类中仍然成立。 2002 年,软件工程大师 Robert C. Martin 出版了一本 Agile Software DevelopmentPrinciples Patterns and Practices ,在文中他把里氏代换原则最终简化为一 句话:“Subtypes must be substitutable for their base types”也就是说子类必须能够替 换成他们的基类。里氏替换原则讲的是基类和子类的关系,只有这种关系存在的时候里氏替换原则才能成立。 里氏替换原则是实现开放封闭原则的具体规范。这是因为:实现开放封闭原则的关键是抽象,而 继承关系又是抽象的一种具体

14、实现。我们大家都打过 CS 的游戏,用枪射击杀人,如下类图:枪的主要职责是射击,如何射击在各个具体的子类中定义。注意在类中调用其他类时务必调用父类或接口,如果不能掉话父类或接口,说明类的射击已经违反了 LSP原则。如果我们有一个玩具手枪,该如何定义呢?我们先在类图2-1上增加一个类ToyGun, 然后继承于Abst ractGun类,修改后的类图如下:玩具枪是不能用来射击的,杀不死人的,这个不应该写shoot方法,在这种情况下业 务的调用类就会出现问题。为了解决这个问题,ToyGun可以脱离继承,建立一个独立的父 类,为了做到代码可以服用,可以与AbstractGun建立关联委托关系,如下图:

15、因此,如果子类不能完整地实现父类的方法,那么建议断开父子继承关系,采用依赖,聚合, 组合等关系代替继承。子类可以有自己的属性或方法。覆盖或实现父类的方法时输入的参数可以放大。覆盖或实现父类的方法时输出结果可以被缩小。这是什么意思呢,父类的方法返回值是一个 类型T,子类相同的方法(覆写)的返回值为类型S,那么根据里氏替换原则就要求S必须小于 等于T,也就是说要么S和T是同一个类型,要么S是T的子类型。采用里氏替换原则的目的就是增加程序的健壮性,需求变更时也可以保持良好的兼容性和稳 定性,即使增加子类,原有的子类可以继续运行。在实际项目中,每个子类对应不同的业务含义, 使用父类作为参数,传递不同的子类完成不同业务逻辑。4依赖倒置原则所谓依赖倒置原则(Dependence Inversion Principle )就是要依赖于抽象,不要依赖于 具体。简单的说就是对抽象进行编程,不要对实现进行编程,这样就降低了客户与实现模块 间的耦合。面向过程的开发,上层调用下层,上层依赖于下层,当下层剧烈变化时,上层也要跟着 变化,这

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

当前位置:首页 > 建筑/环境 > 建筑资料

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