李卫公的长安城

过上一万年,那城就会变成黑色,永远不倒……

  DonewsBlog  |  Donews首页  |  Donews社区  |  Donews邮箱  |  我的首页  |  联系作者  |  聚合   |  登录
  373篇文章 :: 38篇收藏:: 393篇评论:: 5个Trackbacks

公告




版权声明:本 blog 上所有原创文章、图片,未有特别声明者,均遵守 Common Public License。所有翻译、转载文章和图片,版权归属原作者所有,遵守原作者声明。

warning


给我写信

文章

收藏

相册

Focus

Friend's blog

Miscellaneous

My Favourite Blogs

存档


正在读取评论……


翻开任何一本计算机教材,都可以找到面向对象中常用的这几个概念:
对象:对象就是数据+方法的复合体
封装:封装就是隐藏内部的数据
继承:继承就是将抽象类特殊化的过程

有错吗?看起来一点错也没有,然而,在实际开法中,这三种解释极大地限制了我们的思维。
因此,Shalloway和Trott 在 Desing Patterns Explained 中重新解释了这三个概念:

对象

对象不能简单地解释为“数据+方法”,因为按照这种解释,如何构造对象,如何划分对象,都没有确定的标准——对象与对象之间的界限可以随意划定。
对象,应该定义为“具有责任的实体”(an entity that has responsibilities),责任明确了对象的行为。也可以说,对象是有明确行为的实体。
这样定义对象的好处在于,它能够让我们集中关注对象应该具有的行为,而不是具体的实现细节。于是我们可以按照下面的步骤进行开发:
1.不必担心所有的实现细节,先出一个初步的设计(make a prelimianry design without worring about all of the details involved)
2.实现成型的设计(Implement the design achieved)

例如,如果我们要设计一个Shape对象,首先要明确的是Shape的责任:
1.它能够知道自己所处的位置
2.它能够在屏幕上自我展现
3.它能够在屏幕上自我消失
接下来要做的,就是确定一些方法实现上面的功能:
getLocation(...)
drawShape(...)
unDrawShape(...)
这样的开发流程,比开始就解决某个具体方法实现细节的流程要高明得多,高效得多。

封装

封装往往被简单地解释为“隐藏数据”,这没有错,但这种解释给我们的思维造成了很大的限制。
举这样一个例子,有一把“伞”,它不但能够挡雨,还能容纳好几个人,能带我们去这里去那里,有立体声音响,有轮子,有空调,天晴的时候还能开天窗让我们晒太阳——在每个城市都有成千上万的这种“伞”,它就是汽车。
在这个例子中,“汽车”这个对象被封装在“伞”之中,客户端程序仅仅知道这是一把“伞”,而不知道它“其实”是一辆汽车,这就是封装的神秘之处——封装不仅仅可以隐藏数据,还可以隐藏方法(封装类的某一方法可以由其他方法来完成)、隐藏子类(客户端程序只知道一个基类而不知道具体的子类)、隐藏对象(“伞”中隐藏着一辆“汽车”)
再来看一个例子:现有一组Animal对象,需要确切地知道每个Animal运动同一段距离的时间。
麻烦的是,Animal的运动方式有两种,一种是飞,一种是走。如果希望用统一的接口来获得运动所需的时间,一般的解决方法是:设置一个Flag,表明该 Animal到底是飞还是走;或者设置两个Animal的子类,FlyingAnimal和WalkingAnimal;不幸的是,这两种方法都有缺陷:第一种的缺陷在于紧耦合(tight coupling),flag的含义并不确定,而且可能带来混乱;第二种的缺陷在于细节繁密(too many details),而且无法应对某种Animal既能飞又能走的情况。
而封装可以很好地解决这类问题:在Animal中提供统一的AnimalMovement对象,它衍生出两个子类AnimalFly和 AnimalWalk,不同的Animal子类之需要用不同的AnimalMovement子类实例化自己的AnimalMovement对象,就可以实现不同的功能。

继承

继承通常被解释为“创建基类,然后创建继承它们的子类”(create classes, then create deriving new classes based on these base classes),所以术语“特殊化”(specialize)也就意味着从其他类衍生出新的子类。
不过,Shalloway和Trott认为,“继承”有一种更好更强有力(powerful)的定义,即:继承是一种划分对象的方法(a method of classifying objects)。
例如,在基类Shape的标准上衍生出子类Points, Lines, Squares, Circles。我们不妨把它们统统当作Shape,这样会降低考虑和处理的难度,子类的具体特性则由继承加以实现——换句话说,继承关注的不是如何将子类特殊化,而是如何区分子类,实现子类的特征——客户端需要了解的只统一的接口。

封装变数

四人帮(Gang of Four)在 设计模式 中建议,设计时需要认真考虑变数(variable)。也就是说,需要考虑的不是导致重新设计的因素,而是在不重新设计的前提下能变化的因素(Instead of considering what might force a change to desing, consider what you want to be able to change without redesign)。需要封装的,就是这些因素。
在Animal的例子中,我们把AnimalMovement进行了封装,这样做的好处在于,程序应对变化的能力大大增强了——如果将来需要添加一种能游泳的动物,我们只需要实现AnimalSwim作为AnimalMovement的子类,即可,不需要对原有代码作任何改动。



Trackback: http://tb.donews.net/TrackBack.aspx?PostId=512917


[点击此处收藏本文]  发表于2005年08月17日 6:16 AM




正在读取评论……

发表评论

大名:
网址:
验证码
评论