分享

第4章 封装与信息的隐藏 -- 欢迎评论

 linyu2688 2006-08-29
 

第4章 封装与信息的隐藏 -- 欢迎评论

作者:Chuanyan


第4章    封装与信息的隐藏  
interbase    
图4.1显示了肆虐一时的SARS病毒结构图。可以看出,病毒可以分成三个层次:一层坚硬的壳层,壳层外呈触角状的蛋白体,以及壳层内部的遗传物质。显然这种构造使得SARS病毒得以隐藏和保护自身内部结构,这是病毒经过漫长时间的演化形成的有效生存机制。  
无独有偶,面向对象的软件设计中,对象也可以分成三层,一层由各个方法构成的壳层,暴露在壳层外的各个接口,以及受到保护的内部属性,参见图4.2。  
   
   
图4.1、SARS病毒模型。(www.who.org)            图4.2、对象由属性和方法组成,对象向外界提供接口以供操作对象内部属性和触发对象的行为。    
对象的这种结构,使得封装(Encapsulation)与信息隐藏(Information  Hiding)变得可能。封装和信息隐藏常常被混为一谈,但它们并不是一回事。  
4.1    封装  
到底什么是封装呢?让我们还是从四十年前谈起吧。  
如本书在第1章中介绍的,世界上第一个具备面向对象特征的语言是Simula。是Simlua第一次引入了真正意义上的封装。  
在六十年代,模块化编程是基本的设计手段,模块化也是Simula的基本设计思想,只是Simula的模块化非常有特色:模块的设计不是建立在过程之上的,而是建立在真实世界中的物体基础之上的。  
每一个真实的物体都有一些需要模型化的行为,每一个真实的物体都有一些关于其状态的信息。这些物体相互作用,形成了Simula需要描述的模拟系统。Simula的设计师决定以最为接近真实物体的办法进行模拟系统的设计,这样一来,按照真实物体的组织来组织模块,就是顺理成章的了。  
将数据和作用于数据之上的操作绑在一起形成模块,这就是封装。  
一场对象技术的革命就是这样开始的。这场革命开始于封装。  
一个例子:棋盘上的点  
对象是对真实世界中的物体的抽象化,但对象不是照搬真实世界中物体。对象技术中的建模不是把真实世界照搬到软件系统中,对象技术首先要将真实世界理想化、简单化、抽象化,然后把这个改变了的影像搬进软件系统中。  
读者一定建国围棋棋子和棋盘吧,本节就考察一下如何为围棋棋盘上的点建模。  
                 
图4.1、围棋的一间跳、点三三。            图4.2、Point类的类图  
下面的Point类描述在棋盘上的一个点,它带有两条数据,分别代表横纵坐标。这个类可以用UML描述,参见图4.2。  
代码清单4.1、Point类描述棋盘上的点  
public  class  Point  {  
       public  single  x;  
       public  single  y;  
}  
与点相联系的操作有下面这些:  
            移动(move):将这个点对象移动到另一个位置,就好比把一个围棋子从棋盘上的一个点移动到另一个点。  
            计算距离(distance):与这个点与另一个点的距离。围棋手需要计算的比这个要复杂得多。  
要实现这些方法,需要一个新的工具类,不妨称作PointUtil如下  :  
代码清单4.2、操作点的工具类  
public  class  PointUtil  {  
       public  double  distance(Point  p1,  Point  p2){  
               return  Math.sqrt(  (p1.x  -  p2.x)  *(p1.x  -  p2.x)  +  (p1.y  -  p2.y)*(p1.y  -  p2.y));  
       }  
       public  void  move(Point  p,  double  x,  double  y){  
                 p.x  =  x;  
               p.y  =  y;  
       }  
}  
如果要移动一个点,就把这个点传入PointUtil对象的move方法,同时需要传入的还有新的坐标。这个PointUtil对象会把Point对象移动到新的坐标。  
如果要计算一个点到另一个点的距离,就需要把两个点对象传入到PointUtil对象的distance方法中,这个方法会返还你想知道的距离。譬如下面的代码就设定了两个点,并计算出他们的距离:  
代码清单4.3、如何计算两个点之间的距离。  
       public  static  void  main(String[]  args){  
Point  p1  =  new  Point();  
               Point  p2  =  new  Point();  
 
               p1.x  =  10.0F;  
               p1.y  =  20.0F;  
 
               p2.x  =  100.0F;  
               p2.y  =  200.0F;  
 
               PointUtil  putil  =  new  PointUtil();  
               System.out.println(putil.distance(p1,  p2));  
       }  
有两种设计师往往会给出类似于上面的这种设计。  
熟悉过程性设计概念,初学对象技术的设计者常常会给出类似上面的设计。这种对责任的划分方法明显地带有过程式设计的痕迹,因为虽然设计中也使用了类,给人的感觉是如果Java允许把方法放到类外边去,设计者可能会更高兴。Java语言强制设计师使用类,但是使用了类,并不能保证一个设计就真正体现了对象思想的。  
另一类设计者试图原封不动地在软件系统中重现真实世界,他们会认为这是一个好的设计:这难道不是对现实世界的真实描述吗?在现实世界中,围棋子会自己走路吗?难道不是外力移动棋子?棋子难道知道计算距离吗?难道不是一个计算器什么的负责计算距离吗?  
不错,在现实世界中是这样的。但是这个现实世界不是一个理想化的,而是一个蹩脚的现实世界,你不想把这样的现实世界原封不动地搬进软件模型中。  
在一个理想化的世界中,围棋子难道不应当自己会移动吗?外界只需要传送一个消息给棋子,棋子就自动到位。这虽然是想象中的事情,但是并非距离现实很远,只需要借助于一定的电子科技,完全可以在改进的棋子和棋盘上实现这一点。难道你不想把这个聪明的棋子和棋盘当作原型加以引进吗?  
如何划分责任是面向对象的设计与过程性设计的基本区别。如果一个对象包含了某项操作所需的全部数据的话,那么这项操作就应当属于这个对象,而不是属于另一个不能提供所需数据的对象。上面所讨论的move方法需要改变的是Point对象的两个属性:x和y,而这两个属性就在Point对象内,为什么不把move方法交给Point对象呢?  
基于同样的道理,计算一个点与另一个点的距离,需要两个点的坐标,而坐标本就是Point对象的属性,为什么不把这项计算任务交给Point对象呢?当然,这就意味着PointUtil类根本就没有用处,可以取消。  
 
---------------------------------------------------------------  
 
不是评论,说说我的体会或想法。  
封装性不仅仅只是数据或方法的隐藏。《设计模式解析》中解释成任意的封装。例如可以使用Adapter模式将一个类相对于另一个类封装。当然这种情况与搂主要讨论的问题不一样。  
OO中的封装应该从广义上去理解,而不是像以前的书中所讲的一样,不知道这样想有没有什么问题?  
---------------------------------------------------------------  
 
还是拿进阶层次的来讨论吧……入门的章节不值得研究那么多……  
---------------------------------------------------------------  
jeffyan前辈  
我看过一本《JAVA与UML面向对象程序设计》  
The  Essence  of  Object-Oriented  Programming  with  Java  and  UML  
Bruce  E.Wampler写的  
个人觉得这本书对初学者很不错  
 
另外希望您能除了介绍新出炉的UML2.0以外  
还能有其它的新意  
 
---------------------------------------------------------------  
 
jeffyan77(jeffyan77)  :  
 
1.  工具类,类似的还有singleton,在我看来的确不算是OO的手法。不过我并不因此而拒绝使用它们,因为我并不会以OO或非OO简单判定一个技术是对是错。  
"这些工具类中的方法都有共同的特点,第一它们是大都是静态方法,第二它们彼此之间大都没有必然的联系。换言之,它们和所在的类没有什么关系,它们也不应当被放到同一个地方。"  
__________________________________________  
第一点同意;后面的话严重不同意。你可以说“如果...,则说明...“,但是并不能武断地说这是工具类的共性。  
 
2.  过度设计的问题:设计是否过度,本身就是一个经验性很强的东西,而且也不是一个单纯的OO与否的问题。似乎初学者不易理会。  
 
3.  围棋的棋子是不会象象棋一样“移动”的。所以你定义的PointUtil类的Move方法是有问题的,至少不够准确。而且它的两个方法都应该是static的。呵呵。  
 
总体感觉:还不错,例子比较丰富。不过一些比较深入的问题讨论不够,有点中途半端的感觉。如:工具类,过度设计,以及OO和OO语言特性。  
---------------------------------------------------------------  
 
To  jeffyan77(jeffyan77)  :  
 
“本书章节分厂三个层次:入门、进阶层次和选读章节。”  
 
诚心想知道是否在进阶层次有对“过渡设计”的详细实例说明呢?  
同时,划分成入门,进阶这两个层次的依据和目的是什么呢?  
 
单单从你给出的文章片断来讲,我觉得入门这一节其实是对理论的一个概括性的说明。对于是一个行家来说,这些“入门”说明会引起他的共鸣;对于一个初学者来讲,他的理解的到不到位,你是忽略的。我这样说对吧?  
 
     “我想可不可以假定初学者可以直观理解“过度设计”这个词,至于理解的到不到位,反正这一节也不是主要的。”  
 
对于一个初学者,他看了理论的说明之后,他知道了设计的时候不应该去“过渡”。但是由于他并没有与“过度设计”相关的项目经验,所以他其实不能实际体会到“过度设计”这个理论具体应该怎么做。当他想了解具体实际情况的时候,“进阶”的实例就来了。这样推理似乎很合理。  
 
如果先提出理论,然后再加以例子印证的话

    本站是提供个人知识管理的网络存储空间,所有内容均由用户发布,不代表本站观点。请注意甄别内容中的联系方式、诱导购买等信息,谨防诈骗。如发现有害或侵权内容,请点击一键举报。
    转藏 分享 献花(0

    0条评论

    发表

    请遵守用户 评论公约

    类似文章 更多