面象对象设计的原则
来源:互联网 发布:微信收藏夹网络出错 编辑:程序博客网 时间:2024/06/05 17:28
软件设计中存在的问题
什么是好的设计
面向对象的基本设计原则
当存在的问题
过于僵硬(Rigidity)很难加入新功能
过于脆弱(Fragility)很难修改
复用率低(Immobility)高层模块无法重用
黏度过高(Viscosity)破坏原始设计框架
什么是好的设计?
一个好的系统设计应该有如下的性质:可扩展性、灵活性、可插入性。
设计目标
可扩展性(Extensibility)容易添加新的功能
灵活性(Flexibility)代码修改平稳地发生
可插入性(Pluggability)容易将一个类抽出去,同时将另一个有同样接口的类加入进来
面向对象设计的原则
“开-闭”原则(OCP)对可变性封装
里氏替换原则(LSP)如何进行继承
依赖倒转原则(DIP)针对接口编程
接口隔离原则(ISP)恰当的划分角色和接口
合成/聚合复用原则(CARP)尽量使用合成/聚合、尽量不使用继承
Demeter法则(LoD)不要跟陌生人说话
目标与原则的关系
可扩展性(Extensibility)
"开-闭"原则、里氏替换原则、依赖倒转原则、合成/聚合复用原则
灵活性(Flexibility)
"开-闭"原则、Demeter法则、接口隔离原则
可插入性(Pluggability)"开-闭"原则、里氏替换原则、依赖倒转原则、合成/聚合复用原则
开放-封闭原则(OCP)The Open-Closed Principle
任何系统在其生命周期中都会发生变化。如果我们希望开发出的系统不会在第一版本后就抛弃,那么我们就必须牢牢记住这一点。
- Ivar Jacobson
OCP定义
软件组成实体(类,模块,函数,等待)应该是可扩展的,但是不可修改的。
OCP特征
可扩展(对扩展是开放的)
模块的行为功能可以被扩展,在应用需求改变或需要满足新的应用需求时,我们可以让模块以不同的方式工作
不可更改(对更改是封闭的)
这些模块的源代码是不可改动的。任何人都不许修改模块的源代码。
在面向对象设计中,如何通过很小的设计改变就可以应对设计需求的变化,这是令设计者极为关注的问题。为此不少OO先驱提出了很多有关面向对象的设计原则用于指导OO的设计和开发。下面是几条与类设计相关的设计原则。
1. 开闭原则(the Open Closed Principle OCP)
一个模块在扩展性方面应该是开放的而在更改性方面应该是封闭的。因此在进行面向对象设计时要尽量考虑接口封装机制、抽象机制和多态技术。该原则同样适合于非面向对象设计的方法,是软件工程设计方法的重要原则之一。
我们以收音机的例子为例,讲述面向对象的开闭原则。我们收听节目时需要打开收音机电源,对准电台频率和进行音量调节。但是对于不同的收音机,实现这三个步骤的细节往往有所不同。比如自动收缩电台的收音机和按钮式收缩在操作细节上并不相同。因此,我们不太可能针对每种不同类型的收音机通过一个收音机类来实现(通过重载)这些不同的操作方式。但是我们可以定义一个收音机接口,提供开机、关机、增加频率、降低频率、增加音量、降低音量六个抽象方法。不同的收音机继承并实现这六个抽象方法。这样新增收音机类型不会影响其它原有的收音机类型,收音机类型扩展极为方便。此外,已存在的收音机类型在修改其操作方法时也不会影响到其它类型的收音机。
图1是一个应用OCP生成的收音机类图的例子:
图1 OCP应用(收音机)
2. 替换原则 (the Liskov Substitution Principle LSP)
子类应当可以替换父类并出现在父类能够出现的任何地方。这个原则是Liskov于1987年提出的设计原则。它同样可以从Bertrand Meyer 的DBC (Design by Contract) 的概念推出。
我们以学生为例,夜校生为学生的子类,因此在任何学生可以出现的地方,夜校生均可出现。这个例子有些牵强,一个能够反映这个原则的例子时圆和椭圆,圆是椭圆的一个特殊子类。因此任何出现椭圆的地方,圆均可以出现。但反过来就可能行不通。
Liskov的相关图示见图2:
图2 Liskov 原则
运用替换原则时,我们尽量把类B设计为抽象类或者接口,让C类继承类B(接口B┎⑹迪植僮鰽和操作B,运行时,类C实例替换B,这样我们即可进行新类的扩展(继承类B或接口B),同时无须对类A进行修改。
3. 依赖原则 (the Dependency Inversion Principle DIP)
在进行业务设计时,与特定业务有关的依赖关系应该尽量依赖接口和抽象类,而不是依赖于具体类。具体类只负责相关业务的实现,修改具体类不影响与特定业务有关的依赖关系。
在结构化设计中,我们可以看到底层的模块是对高层抽象模块的实现(高层抽象模块通过调用底层模块),这说明,抽象的模块要依赖具体实现相关的模块,底层模块的具体实现发生变动时将会严重影响高层抽象的模块,显然这是结构化方法的一个"硬伤"。
面向对象方法的依赖关系刚好相反,具体实现类依赖于抽象类和接口(见图-3)。
为此,我们在进行业务设计时,应尽量在接口或抽象类中定义业务方法的原型,并通过具体的实现类(子类)来实现该业务方法,业务方法内容的修改将不会影响到运行时业务方法的调用。
图3依赖原则图示
4. 接口分离原则(the Interface Segregation Principle ISP)
采用多个与特定客户类有关的接口比采用一个通用的涵盖多个业务方法的接口要好。
ISP原则是另外一个支持诸如COM等组件化的使能技术。缺少ISP,组件、类的可用性和移植性将大打折扣。
这个原则的本质相当简单。如果你拥有一个针对多个客户的类,为每一个客户创建特定业务接口,然后使该客户类继承多个特定业务接口将比直接加载客户所需所有方法有效。
图4展示了一个拥有多个客户的类。它通过一个巨大的接口来服务所有的客户。只要针对客户A的方法发生改变,客户B和客户C就会受到影响。因此可能需要进行重新编译和发布。这是一种不幸的做法。
图4 带有集成接口的服务类
我们再看图-5中所展示的技术。每个特定客户所需的方法被置于特定的接口中,这些接口被Service类所继承并实现。
图5 使用接口分离的服务类设计
如果针对客户A的方法发生改变,客户B和客户C并不会受到任何影响,也不需要进行再次编译和重新发布。
以上四个原则是面向对象中常常用到的原则。此外,除上述四原则外,还有一些常用的经验诸如类结构层次以三到四层为宜、类的职责明确化(一个类对应一个具体职责)等可供我们在进行面向对象设计参考。但就上面的几个原则看来,我们看到这些类在几何分布上呈现树型拓扑的关系,这是一种良好、开放式的线性关系、具有较低的设计复杂度。一般说来,在软件设计中我们应当尽量避免出现带有闭包、循环的设计关系,它们反映的是较大的耦合度和设计复杂化。
- 面象对象设计的原则
- 面象对象设计的原则
- 面象对象设计原则
- 面象对象设计的基本原则
- 面象对象设计6大原则之二:开放封闭原则
- 面象对象设计6大原则之六:迪米特原则
- 面象对象设计6大原则之五:依赖倒置原则
- 面象对象设计6大原则之四:接口隔离原则
- 面象对象设计6大原则之三:里氏替换原则
- 面象对象设计6大原则之一:单一职责原则
- JavaScript面象对象设计
- 面象对象设计总结
- 面象对象的面试题
- 面象对象与实际的结合
- 面象对象的三大特点
- 面象对象
- java 面象对象
- C#面象对象1
- TCUA中资源池的使用
- 人类的运动也可以产生电力
- OO设计原则总结
- 执子之手 网络流传原文
- 面象对象设计的基本原则
- 面象对象设计的原则
- UVa Problem 10159 Star (六角星)
- Siri本地化的必然
- 结构模式之桥梁模式注解
- 菜鸟修炼C语言小设计之——工资统计
- window.open 后A 和 B 窗口的访问
- MyEclipse 出错提示 Can not find the tag library descriptor for "http://java.sun.com/jsp/jstl/core"
- linphone 介绍
- BI---我的商业智能