<HTML>
<HEAD>
<META http-equiv="Content-Type" content="text/html; charset=gb2312">
<TITLE>面向对象设计的基本原则</TITLE>
<style type="text/css">
.content {
font-size: 13px;
line-height: 20px;
padding: 5px 10px 5px 10px;
}
.title1 {
font-size: 18px;
font-weight: bold;
height: 40px;
text-align: center;
vertical-align: middle;
color: #759B00;
padding: 5px 10px 5px 10px;
}
.bbold {
font-size: 13px;
color: #759B00;
font-weight: bolder;
}
</style>
</HEAD>
<BODY bgcolor="#add8e6">
<h1 class="title_txt" >
面向对象设计的基本原则!
</h1>
<div style="TEXT-INDENT: 21pt" class="content">
正如牛顿三大定律在经典力学中的位置一样,“开-闭”原则(Open-Closed
Principle)是面向对象的可复用设计(Object Oriented
Design或OOD)的基石。其他设计原则(里氏代换原则、依赖倒转原则、合成/聚合复用原则、迪米特法则、接口隔离原则)是实现“开-闭”原则的手段和工具。
</div>
<div>
</div>
<div>
<strong>一、“开-</strong><strong>闭”原则(Open-Closed
Principle,OCP</strong><strong>)</strong>
</div>
<div style="TEXT-INDENT: 21pt " class="content">
<strong>1.1</strong><strong>“开-</strong><strong>闭”原则的定义及优点</strong>
</div>
<div style="TEXT-INDENT: 21pt" class="content">
1)定义:一个软件实体应当对扩展开放,对修改关闭( Software entities should be open for
extension,but closed for
modification.)。即在设计一个模块的时候,应当使这个模块可以在不被修改的前提下被扩展。
</div>
<div style="TEXT-INDENT: 21pt" class="content">
2)满足“开-闭”原则的系统的优点
</div>
<div style="TEXT-INDENT: 21pt " class="content">
a)通过扩展已有的软件系统,可以提供新的行为,以满足对软件的新需求,使变化中的软件系统有一定的适应性和灵活性。
</div>
<div style="TEXT-INDENT: 21pt " class="content">
b)已有的软件模块,特别是最重要的抽象层模块不能再修改,这就使变化中的软件系统有一定的稳定性和延续性。
</div>
<div style="TEXT-INDENT: 21pt " class="content">
c)这样的系统同时满足了可复用性与可维护性。
</div>
<div style="TEXT-INDENT: 21pt " class="content">
<strong>1.2</strong><strong>如何实现“开-</strong><strong>闭”原则</strong>
</div>
<div style="TEXT-INDENT: 21pt " class="content">
在面向对象设计中,不允许更改的是系统的抽象层,而允许扩展的是系统的实现层。换言之,定义一个一劳永逸的抽象设计层,允许尽可能多的行为在实现层被实现。
</div>
<div style="TEXT-INDENT: 21pt " class="content">
解决问题关键在于抽象化,抽象化是面向对象设计的第一个核心本质。
</div>
<div style="TEXT-INDENT: 21pt " class="content">
对一个事物抽象化,实质上是在概括归纳总结它的本质。抽象让我们抓住最最重要的东西,从更高一层去思考。这降低了思考的复杂度,我们不用同时考虑那么多的东西。换言之,我们封装了事物的本质,看不到任何细节。
</div>
<div style="TEXT-INDENT: 21pt " class="content">
在面向对象编程中,通过抽象类及接口,规定了具体类的特征作为抽象层,相对稳定,不需更改,从而满足“对修改关闭”;而从抽象类导出的具体类可以改变系统的行为,从而满足“对扩展开放”。
</div>
<div style="TEXT-INDENT: 21pt " class="content">
对实体进行扩展时,不必改动软件的源代码或者二进制代码。关键在于抽象。
</div>
<div style="TEXT-INDENT: 21pt " class="content">
<strong>1.3</strong><strong>对可变性的封装原则</strong>
</div>
<div style="TEXT-INDENT: 21pt " class="content">
“开-闭”原则也就是“对可变性的封装原则”(Principle of
Encapsulation of Variation
,EVP)。即找到一个系统的可变因素,将之封装起来。换言之,在你的设计中什么可能会发生变化,应使之成为抽象层而封装,而不是什么会导致设计改变才封装。
</div>
<div style="TEXT-INDENT: 21pt " class="content">
对可变性的封装原则”意味着:
</div>
<div style="TEXT-INDENT: 21pt " class="content">
a)一种可变性不应当散落在代码的许多角落,而应当被封装到一个对象里面。同一可变性的不同表象意味着同一个继承等级结构中的具体子类。因此,此处可以期待继承关系的出现。继承是封装变化的方法,而不仅仅是从一般的对象生成特殊的对象。
</div>
<div style="TEXT-INDENT: 21pt " class="content">
b)一种可变性不应当与另一种可变性混合在一起。作者认为类图的继承结构如果超过两层,很可能意味着两种不同的可变性混合在了一起。
</div>
<div style="TEXT-INDENT: 21pt " class="content">
使用“可变性封装原则”来进行设计可以使系统遵守“开-闭”原则。
</div>
<div style="TEXT-INDENT: 21pt " class="content">
即使无法百分之百的做到“开-闭”原则,但朝这个方向努力,可以显著改善一个系统的结构。
</div>
<div>
<strong>二、里氏代换原则(Liskov Substitution Principle, LSP</strong><strong>)</strong>
</div>
<div style="TEXT-INDENT: 21pt " class="content">
<strong>2.1</strong><strong>概念</strong>
</div>
<div style="BACKGROUND: white; TEXT-INDENT: 21pt" class="content">
定义:
<span style="COLOR: black">如果对每一个类型为</span><span style="COLOR: black">T1</span><span
style="COLOR: black">的对象</span><span style="COLOR: black">O1</span><span
style="COLOR: black">,都有类型为</span><span style="COLOR: black">T2
</span><span style="COLOR: black">的对象</span><span style="COLOR: black">O2</span><span
style="COLOR: black">,使得以</span><span style="COLOR: black">T1</span><span
style="COLOR: black">定义的所有程序</span><span style="COLOR: black">P</span><span
style="COLOR: black">在所有的对象</span><span style="COLOR: black">O1</span><span
style="COLOR: black">都代换为</span><span style="COLOR: black">O2</span><span
style="COLOR: black">时,程序</span><span style="COLOR: black">P</span><span
style="COLOR: black">的行为没有变化,那么类型</span><span style="COLOR: black">T2</span><span
style="COLOR: black">是类型</span><span style="COLOR: black">T1</span><span
style="COLOR: black">的子类型。</span>
</div>
<div style="BACKGROUND: white; TEXT-INDENT: 21pt" class="content">
<span style="COLOR: black">即,一个软件实体如果使用的是一个基类的话,那么一定适用于其子类。而且它觉察不出基类对象和子类对象的区别。</span>也就是说,在软件里面,把基类都替换成它的子类,程序的行为没有变化。
</div>
<div style="BACKGROUND: white; TEXT-INDENT: 21pt" class="content">
<span style="COLOR: black">反过来的代换不成立,如果一个软件实体使用的是一个子类的话,那么它不一定适用于基类。</span>
</div>
<div style="TEXT-INDENT: 21pt " class="content">
任何基类可以出现的地方,子类一定可以出现。
</div>
<div style="TEXT-INDENT: 21pt " class="content">
基于契约的设计、抽象出公共部分作为抽象基类的设计。
</div>
<div style="TEXT-INDENT: 21pt " class="content">
<strong>2.2</strong><strong>里氏代换原则与“开-</strong><strong>闭”原则的关系</strong>
</div>
<div style="TEXT-INDENT: 21pt " class="content">
实现“开-闭”原则的关键步骤是抽象化。基类与子类之间的继承关系就是抽象化的体现。因此里氏代换原则是对实现抽象化的具体步骤的规范。
</div>
<div style="TEXT-INDENT: 21pt " class="content">
违反里氏代换原则意味着违反了“开-闭”原则,反之未必。
</div>
<div>
<strong>三、 </strong><strong>依赖倒转原则</strong><strong>(</strong><strong>dependence
inversion principle, DIP</strong><strong>)</strong>
</div>
<div style="TEXT-INDENT: 21pt " class="content">
<strong><span>
3.1</span>
</strong><strong>概念</strong>
</div>
<div style="TEXT-INDENT: 21pt " class="content">
<strong>依赖倒转原则</strong>就是要依赖于抽象,不要依赖于实现。(Abstractions
should not depend upon details. Details should depend upon
abstractions.)要针对接口编程,不要针对实现编程。(Program to an interface, not an
implementation.)
</div>
<div style="TEXT-INDENT: 21pt " class="content">
也就是说应当使用接口和抽象类进行变量类型声明、参数类型声明、方法返还类型说明,以及数据类型的转换等。而不要用具体类进行变量的类型声明、参数类型声明、方法返还类型说明,以及数据类型的转换等。要保证做到这一点,一个具体类应当只实�