架构师训练营 week2 学习总结
面向对象设计认知
什么是对象?
Booch 对于对象的描述:对象具有状态、行为和标识。
状态:表明每个对象可以有自己的数据。
行为:表明每个对象可以产生行为。
标识:表明每个对象都区别于其它的对象。(唯一的地址)
面向对象编程的三要素(特征)
封装性(Encapsulation)
隐藏实现细节(访问控制)
定义接口
继承性(Inheritance)
IS-A 关系
HAS-A 关系(组合)
多态性(Polymorphism)
后期绑定(虚函数)
向上转形(Up Casting)
面向对象编程与面向对象分析
面向对象编程不是使用面向对象的编程语言进行编程,而是利用多态特性进行编程。
面向对象分析是将客观世界,即编程的业务领域进行对象分析。
充血模型与贫血模型
领域驱动设计 DDD
面向对象设计的目的和原则
面向对象设计的目的
强内聚、低耦合,从而使系统
Ø 易扩展 - 易于增加新的功能
Ø 更强壮 - 不容易被粗心的程序员破坏
Ø 可移植 - 能够在多样的环境下运行
Ø 更简单 - 容易理解、容易维护
面向对象设计的原则
为了达到上述设计目标,有人总结出了多种指导原则
“原则”是独立于编程语言的,甚至也可以用于非面向对象的编程语言中。
设计模式(design patterns)
设计模式是用于解决某一种问题的通用的解决方案。
设计模式也是语言中立的。
设计模式贯彻了设计原则。
Gang of Four(Erich Gamma, Richard Helm, Ralph Johnson and John Vlissides)提出了三
大类 23 种基本的设计模式:
创建模式
行为模式
结构模式
在更细分的领域当中还可以总结出许多设计模式:
并发编程模式
Java EE 模式
etc.
框架(frameworks)
框架是用来实现某一类应用的结构性的程序, 是对某一类架构方案可复用的设计与实现
如同框架结构的大厦的框架
简化应用开发者的工作
实现了多种设计模式,使应用开发者不需要花太大的力气,就能设计出结构良好的程序来
不同领域的框架
微软公司为 Windows 编程开发了 MFC 框架。
Java 为它的 GUI(图形用户界面)开发了 AWT 框架。
还有许多开源的框架:MyBatis,Spring 等。
Web 服务器也是框架:Tomcat
框架 VS 工具
框架调用应用程序代码
应用程序代码调用工具
架构师用框架保证架构的落地
架构师用工具提高开发效率
面向对象设计原则
软件设计的最终目的,是使软件达到“强内聚、松耦合”,从而使软件:
易扩展 - 易于增加新的功能
更强壮 - 不容易被粗心的程序员破坏
可移植 - 能够在多样的环境下运行
更简单 - 容易理解、容易维护
与之相反,一个“不好的”软件,会发出如下“臭味”:
僵硬 - 不易改变。
脆弱 - 只想改 A,结果 B 被意外破坏。
不可移植 - 不能适应环境的变化。
导致误用的陷阱 - 做错误的事比做正确的事更容易,引诱程序员破坏原有的设计。
晦涩 - 代码难以理解。
过度设计、copy-paste 代码。
OOD 原则一:开/闭原则(OCP)
OCP - Open/Closed Principle
对于扩展是开放的(Open for extension)
对于更改是封闭的(Closed for modification)
简言之:不需要修改软件实体(类、模块、函数等),就应该能实现功能的扩展。
传统的扩展模块的方式就是修改模块的源代码。如何实现不修改而扩展呢?
关键是抽象!
OOD 原则二:依赖倒置原则(DIP)
DIP - Dependency Inversion Principle
高层模块不能依赖低层模块,而是大家都依赖于抽象;
抽象不能依赖实现,而是实现依赖抽象。
DIP 倒置了什么?
模块或包的依赖关系
开发顺序和职责
软件的层次化
高层决定低层
高层被重用
框架的核心
好莱坞规则:
Don't call me, I'll call you.
倒转的层次依赖关系
OOD 原则三:Liskov 替换原则(LSP)
在 Java/C++ 这样的静态类型语言中,实现 OCP 的关键在于抽象,而抽象的威力在于多
态和继承。
一个正确的继承要符合什么要求呢?
答案:Liskov 替换原则
1988 年,Barbara Liskov 描述这个原则:
若对每个类型 T1 的对象 o1,都存在一个类型 T2 的对象 o2,使得在所有针对 T2 编写的程
序 P 中,用 o1 替换 o2 后,程序 P 的行为功能不变,则 T1 是 T2 的子类型。
简言之:子类型(subtype)必须能够替换掉它们的基类型(base type)。
从“契约”的角度来看 LSP
LSP 要求,凡是使用基类的地方,一定也适用于其子类。
从 Java 语法角度看,意味着:
子类一定得拥有基类的整个接口。
子类的访问控制不能比基类更严格。
Ø 例如,Object 类中有一个方法:
Ø
protected Object clone();
Ø 子类中可以覆盖(override)之并放松其访问控制:
Ø
public Object clone();
Ø 但反过来是不行的,例如:
Ø 覆盖 public String toString() 方法,并将其访问控制缩小成 private,编译器不可能允许这样的代码通过编译。
从更广泛的意义来看,子类的“契约”不能比基类更“严格”
例如,正方形长宽相等,这个契约比长方形要严格,因此正方形不是长方形的子类。
例如,Properties 的契约比 Hashtable 更严格。
继承 vs. 组合
继承和组合是 OOP 的两种扩展手段
继承的优点:
比较容易,因为基类的大部分功能可以通过继承直接进入子类。
继承的缺点:
继承破坏了封装,因为继承将基类更多的细节暴露给子类。因而继承被称为“白盒复用”。
当基类发生改变时,可能会层层影响其下的子类。
继承是静态的,无法在运行时改变组合。
类数量的爆炸。
应该优先使用组合
OOD 原则四:单一职责原则(SRP)
SRP - Single Responsibility Principle
又被称为“内聚性原则(Cohesion)”,意为:
Ø 一个模块的组成元素之间的功能相关性。
将它与引起一个模块改变的作用力相联,就形成了如下描述:
Ø 一个类,只能有一个引起它的变化的原因。
什么是职责?
单纯谈论职责,每个人都会得出不同的结论
因此我们下一个定义 :
Ø 一个职责是一个变化的原因。
OOD 原则五:接口分离原则(ISP)
ISP - Interface Segregation Principle
不应该强迫客户程序依赖它们不需要的方法。
ISP 和 SRP 的关系
ISP 和 SRP 是相关的,都和“内聚性”有关。
SRP 指出应该如何设计一个类 —— 只能有一种原因才能促使类发生改变。
ISP 指出应该如何设计一个接口 —— 从客户的需要出发,强调不要让客户看到他们不需要
的方法。
版权声明: 本文为 InfoQ 作者【花果山】的原创文章。
原文链接:【http://xie.infoq.cn/article/fdf0042ac00449c5adda04af7】。未经作者许可,禁止转载。
评论