面向对象设计原则
高内聚是指相近的功能、行为应该放到同一个组件中。
设计原则
高內聚、低耦合
什么是“高内聚”
高内聚是指相近的功能、行为应该放到同一个组件中。
什么是“低耦合”
组件间的依赖关系清晰,交互不复杂。
面向对象编程、面向对象分析
面向对象编程不是使用面向对象的编程语言进行编程,而是利用多态特性进行编程,面向对象语言真正区别于其他高级语言的地方是多态
。
框架(frameworks)
框架是用来实现某一类应用的结构性程序,是对某一类架构方案可复用的设计与实现。
架构师通过开发或者维护框架来把控系统的质量。
面向对象设计的基本原则
OOD 原则一:开/闭原则(OCP)
OCP - Open/Closed Principle
对扩展是开放的(Open for extension)
对更改是封闭的(Closed for modification)
不需要修改现有软件实体,就能实现功能扩展
。
实现不修改而扩展的关键是
抽象
。
DEMO
设计一个控制电话拨号的软件。
“拨打电话”的 Use Case描述:
我们按下数字按钮,屏幕上显示号码,扬声器发出按键音
我们按下Send按钮,系统接通无线网络,同时屏幕上显示正在拨号。
不太优雅的设计
类图
Demo Code
坏味道
僵硬 - 不易增加、修改:增加一种Butn类型,就需要对 Button类进行修改;修改 Dialer,可能会影响 Button。
脆弱- switch case/if elsei语句是相当脆弱的。当我想修改Send按钮的功能时,有可能不小心破坏数字按钮当这种函数很多时,我很有可能会漏掉某个函数,或其中的某个条件分支。
不可移植-设想我们要设计密码锁的按钮,它只需要数字按键,但 Button的设计使它必须附带”send”类型的按钮。
改进 Button:方法一
抽象 Button 接口,分别实现 DigitButton 和 SendButton 实现类,分别调用 Dialer 业务方法。Dialer 类内部通过 if-else 判断决定,分别执行 digit/send。
改进 Button:策略模式
抽象 ButtonServer 接口,声明 ButtonServer#buttonPressed(int token) 方法,在 Dialer 中实现该方法,供 Button#process 调用。
Button 类伪代码
改进 Button:适配器模式
定义两个 Adepter 类实现 ButtonServer 接口,分别调用 Dialer 类的 digit/send 方法。Dialer 和 ButtonServer 解耦,去除掉了 if-else 逻辑。
DigitButtonDailerAdepter 类伪代码:
SendButtonDailerAdepter 类伪代码:
在此基础上新的需求:
同一 Button 同时需要触发多个功能。e.g. 点亮电话的灯。
可以通过增加新的 Adepter 来聚合不同的方法。
LampAndDigitButtonDailerAdepter 类伪代码:
改进 Button:观察者模式
应对一个 button 按钮需要触发多个功能需求。
接口 ButtonServer 修改为 ButtonListener。
Button 类添加 List buttonListeners 字段,添加 addButtonListener(ButtonListener buttonListener) 方法。
Button#process 方法调整为迭代执行 buttonListeners 内所有对象。
phone 类组装
满足开闭原则,对功能扩展有较好的支持。
Phone 类伪代码:
OOD原则ニ:依赖倒置原则(DIP)
DIP - Dependency Inversion Principle
高层模块不依赖低层模块,而是依赖抽象。
抽象不依赖实现,而是实现依赖抽象。
DIP 倒置了什么?
模块或者包的依赖关系
开发顺序和职责(高层来定义、来调用)
软件的层次化
高层决定低层
高层被重用
e.g. Controller 层定义接口,自己调用, Service 层负责实现这个接口。
反例:
修改:
框架的核心
好莱坞原则:
Don't call me, I'll call you.
倒转的层次依赖关系。
应用不要调用框架,框架会来调用应用层实现。依赖是反过来的。
ooD原则三: Liskova替换原则(LSP)
子类必须能替换掉基类。
凡是使用基类的地方,一定也适用于其子类。
e.g. 人不能骑马,但是不能骑小马,违反原则。
子类抛出来的异常是父类抛出来的异常的子类,否则基类 catch 不到子类异常。
继承违反原则的时候使用组合(适配器模式)。
OOD原则四:单一职责原则(SRP)
SRP - Single Responsibility Principle
一个类只有一个引起它改变的原因。
单个类的职责少一些。
e.g.
改进
区分类的方法:分清职责
职责: 变化的原因
如果实现类不可拆分,采用接口隔离,分离职责。
OOD原则五:接口分离原则(ISP)
ISP - Interface Segregation Principle
不应该强迫客户程序依赖它们不需要的方法。
客户端看不到不需要的方法。
不暴露给客户端不需要的方法。
不要为了复用方法继承基类。
ISP和SRP的关系
ISP和SRP是相关的,都和“内聚性”有关。
SRP指出应该如何设计ー一个类ーー只能有一种原因才能促使类发生改变。
ISP指出应该如何设计一个接口ーー从客户的需要出发,强调不要让客户看到他们不需要的方法。
总结
OOD 原则
开/闭原则(OCP)
依赖倒置原则(DIP)
Liskova替换原则(LSP)
单一职责原则(SRP)
接口分离原则(ISP)
版权声明: 本文为 InfoQ 作者【陈皮】的原创文章。
原文链接:【http://xie.infoq.cn/article/19192d5104d13496c1da9796f】。文章转载请联系作者。
评论