首页 / 软件开发 / JAVA / 冒号和他的学生们(连载24)——对象封装
冒号和他的学生们(连载24)——对象封装2011-07-03 BlogJava 郑晖24.对象封装阴阳地理两分张,隐者为阴显者阳 ——《玉髓经.曜星论》“用广东话说,真是有型有料又有性格啊!”叹号啧啧连声,“这哪里是在设计软件,分明是在设计心仪的对象嘛。”“我们可不就是在谈对象设计吗?”冒号笑着反问,“在OOP的世界里,每位程序员都是造物主。保持热情、专注力和审美情趣,说不定哪一天就像希腊神话里的皮格玛利翁一样,雕塑的美女变活了。”“哇,那可就美了!”逗号极尽夸张之调。全班哄堂大笑。“刚才提到抽象是OOP三大基本特性的基础,下面我们逐个剖析。”冒号很快收拢了话题,“首当其冲的是封装性。记得前面谈对象范式时,引号曾试图为我们解释封装性,可惜被我无情地打断了。现在我们请他继续讲解吧。”在众人逗趣式的掌声中,引号竟有些腼腆了:“所谓封装性,就是将数据与相关行为包装在一起以实现信息隐藏。”“几乎无懈可击。”冒号赞扬得有些保守,“那么封装(encapsulation)与信息隐藏(information hiding)有区别吗?”“应该是一回事吧。”在冒号的逼视下,引号有些犹豫了,“嗯。。。信息隐藏是一种原则,而封装是实现这种原则的一种方式。”“言之有理!”冒号这回赞扬得很干脆,“尽管大多数参考书对二者不加区分,我还是要解析一番。其实广义的封装仅仅只是一种打包,即package或bundle,是密封的但可以是透明的。或者说,封装就是把一些数据和方法装在一个封闭的盒子里——可能是黑盒子,也可能是白盒子。从语法上说,这是OOP与诸如C之类的过程式语言最大的不同。请问这带来什么效果?”句号反应很快:“这等于引入了一种新的模块机制,将相关的数据和作用其上的运算捆绑在一起形成被称为类的模块。”“回答正确!”冒号很满意,“刚才我们用C实现了队列,但由于C不支持封装,只能以文件形式来划分模块,显然不如类划分那么方便和明晰。此外,封装还有语法糖(Syntactic sugar)效果。”问号好奇地问:“什么是语法糖?是不是很甜?”“所谓语法糖,就是一些语法上的甜头。它不是核心语法,并没有提供任何额外的功能,只是用起来更简洁实用、更自然方便,看起来更酷、更炫而已。”冒号有意用时髦的词汇来填补代沟,“我们知道,过程式函数采用谓语(主语,宾语)的形式,而OOP采用主语.谓语(宾语)的形式。”“哦,就是那个狗吃屎和吃狗屎啊,那可不甜。”逗号又来插科打诨。众人笑得前仰后合。冒号不为所动:“再拿队列为例,如果增加一个队列成员,用刚才的C实现,我们需要写下:queue_add(queue, item)。假如用Java来实现,只需写queue.add(item)。由于封装使add绑定在queue上,一方面可以将对象queue前置,既更符合自然语言,又少敲一个字符;另一方面,这种绑定使add局限于Queue类中,因此不必加上‘queue_’的前缀以防与其他类的方法函数名相冲突。这同样节省了打字,也使接口更简单。”句号提出:“如果C支持函数重载(overload),那么‘queue_’的前缀就可省去。”“你说的既对也不对。”冒号辩证地评判,“如果C支持重载,该前缀的确能省去;但从另一角度看,即使Java或C++不支持重载,前缀用样能省去。因为函数add已经不再是全局函数,Queue类就是其上下文(context)。换句话说,分属不同类的函数是不可能产生歧义(ambiguity)的,哪怕它们的签名(signature)一模一样。因此我们要把功劳记在封装的名下。”句号心悦诚服。