隐藏复杂性,是我们人类处理更复杂问题的一种常用方法。这可能跟人的记忆力、计算力等是有限的这点有关,对这种方法背后原因的深度挖掘,要涉及人类认知学方面的知识,而显然它(认知学)的表现并不尽如人意,否则完全可以根据它造出会认知的机器来。
这里不讨论认知学与强人工智能,感兴趣的读者可以找些这方面的资料来读。我们只要知道,这种隐藏复杂性的方法很常用、很好用就可以了,比如操作电视,我们不需要知道电视内部的繁杂的布线,只通过几个电视按钮就可以实现调整音量、切换频道等等功能;软件中,面向对象中的封装,就是对这一基本方法的体现。
对象的封装,要分两个方面来考察,一个是怎么样封装才算对,一个是怎么样封装才算好。
达到了封装者对对象的职责预期就是对的,否则,就是错的。
比如,想得到的是一个狗对象,能狗叫,而封装的结果竟然是个猫,会猫叫。又比如,想得到的是一个狗对象,能狗叫,而封装的结果是一个狗对象,却能猫叫。这都是没有达到封装预期所致。但也有这种情况,有人先封装了一个对象后,接着说,这个对象就是我的预期,这样做就像打哪儿指哪儿的神枪手一样,预期永远与封装的对象相符合,那么我们只能考察它的另一项指标:好不好。
而评价封装的好不好,很难有一个客观的标准,不管从哪个角度说,,它都更属于设计美学范畴。当一种封装显得不怎么美的时候,就是不太好。怎么又算美呢?这真的很难说;一千个人可能会有一千种关于美的评价吧。我只能说一下我自己的审美倾向,简洁既是美。
简洁的追求会自然促使你让类的职责单一,比如一个狗对象,不但会狗叫,也能猫叫,那么猫叫就是很不和谐的音符,这就显得不美。狗对象只表现狗的行为则显得更为合适,表现的太多,反而会感觉很怪异。假如来了只猫对象,见到这只会猫叫的狗,一定感觉很不是滋味。程序是给程序员看的,职责明确而接口简单的对象,看起来会更舒服,可读性也一定会更好。职责模糊而接口复杂的对象,看起来总不那么舒服(虽然也能实现所有业务功能)。
我们还是看一段具体的程序吧。这是一个计数器程序。
这个类只有一个属性,对应到这个对象,则这个类属性代表着对象的状态,所有的方法,都是围绕着对象的基本属性或状态进行的操作,没有和基本属性无关的操作。这个对象的职责就是负责计数。很简洁。假如我们再添加一个方法,如下:
public int max(int a,int b){
if(a>b) return a;
else return b;
}
那么这个方法对于这个计数器对象来说,就是相当于狗对象中有了猫叫,就是不和谐的,就是不美的。这个方法和计数器的职责是无关的,它也没有涉及到类属性的任何操作,如果一个操作对它自身没有任何影响,这好像更应该是别的对象的方法。所以,把取得最大值这种方法放在这里是很累赘的。
既然是在进行封装和信息隐藏,就要区别于开放和信息暴露,那么在能完成特定职责的情况下,封的越严实越好,信息隐藏的越多越好,留的接口越少越好,这样的对象的功能才强大而接口又简洁。这种简洁的美感怎么表述呢,我总认为苹果公司的各种产品的界面设计最能体现出这种简洁美感。IPod的界面和操作设计,就有一种艺术般的简洁美感。而面向对象设计中的封装,也应该向iPod的封装效果学习。
比如两个同类型对象,如果它们的id属性相等,则认为这两个对象相等。有两种办法判断相等,一种是分别通过两个对象提供的接口取出对象id,再在对象外的程序中做id的比较逻辑判断(例如:if a.id=b.id then…);一种是对象本身提供是否相等的方法,在对象内部完成此判断,外人看不到(例如:if a.equal(b) then…)。这样,把实现细节隐藏在内部,显然这样的封装的更加合理,使用起来也更加的方便。这就像操作轿车,如果轿车的接口是这样:按一个按钮,弹出一根线,再按下另一个按钮,弹出另一根线,然后司机用手把两根线一碰,汽车发动了!虽然也能发动汽车,但未免太麻烦了;这种发动汽车的方式就像比较两个对象是否相等的例子中的前者,这样做肯定也是能发动着汽车的,就像很多封装的不好的对象一样能实现要求的功能一样(比如比较对象是否相等的第一个例子)。一拧钥匙,汽车就发动,明显优于手工碰线头的方式。
一想起封装与信息隐藏,我总是会不由自主的想起《自私的基因》一书的作者道金斯说的关于基因的一段话:
但在今日,别以为它们(基因)还会浮游于海洋之中了。很久以前,它们已经放弃了这种自由自在的生活方式了。在今天,它们群集相处,安稳地寄居在庞大的步履蹒跚的“机器”人体内,与外界隔开来,通过迂回曲折的间接途径与外部世界联系,并通过遥控操纵外部世界。它们存在于你和我的躯体内;它们创造了我们,创造了我们的肉体和心灵;而保存它们正是我们存在的终极理由。这些复制基因源远流长。今天,我们称它们为基因,而我们就是它们的生存机器。
他的这段话如此精彩,令我忍不住套用如下:
基本的变量已经不再浮游于一大段一大段的程序中了,它们已经放弃了(其实是程序员不用这种方式了)这种自由自在的存在方式,而是安稳的寄居于庞大而蹒跚的“对象”内部,与外界隔开来,通过迂回曲折的间接途径与外部世界联系和通信。而这些对象,就是它们这些基本变量的生存机器!
分享到:
相关推荐
面向对象之封装.xmind
封装是面向对象三大特性之一,其他两个是继承和多态。封装是将数据和操作这些数据的方法捆绑在一起,形成一个独立的单元,也就是类。这样可以保护数据不被外部随意访问,提高代码的安全性和可维护性。下面我们将深入...
标题“axios 面向对象封装”表明我们将创建一个自定义的 Axios 实例,它可以作为一个独立的对象在多个模块或组件之间复用。这种封装通常包括创建一个构造函数,用于初始化配置,以及定义一些方法,如发送GET、POST等...
Java 面向对象编程之封装、继承、多态 本文将对 Java 面向对象编程的三大特性:封装、继承、多态进行详细的解释和分析。 一、封装 封装是面向对象编程的基本特性之一,指的是将数据和操作数据的方法封装在一起,...
Educoder题目:Java面向对象 - 封装、继承和多态答案解析
Educoder题目:Java面向对象 - 封装、继承和多态的综合练习答案解析
在学习Java面向对象编程时,封装是实现信息隐藏的重要机制之一。它主要是指通过访问修饰符限制类成员的访问权限,从而达到隐藏类内部细节的目的。封装不仅提高了程序的安全性,也使得代码更加模块化,易于维护和复用...
本页面提供面向对象单例封装mysqli数据库 面向对象单例封装mysqli数据库 确定可用
标题“C语言实现面向对象编程之封装代码”指的是利用C语言来实现面向对象编程中的封装特性。封装是面向对象三大特性之一,它的核心思想是将数据和操作这些数据的方法绑定在一起,作为一个整体——即对象来处理,对...
在描述中提到的“面向对象封装的视觉函数OOP”是指利用LabVIEW的面向对象编程特性来封装视觉处理功能。面向对象编程(Object-Oriented Programming,简称OOP)是一种编程范式,它通过类和对象的概念来组织代码,使得...
本文实例讲述了Python 面向对象之封装、继承、多态操作。分享给大家供大家参考,具体如下: 封装、继承、多态 是面向对象的3大特性 为啥要封装 好处 在使用面向过程编程时,当需要对数据处理时,需要考虑用哪个...
在本文中,我们将深入探讨“Lua面向对象封装”这一主题,结合给定的文件名“CC_Object.lua”和“Luatest1.lua”,推测这是关于在Lua中实现面向对象编程(OOP)的示例代码。 首先,让我们理解Lua中的面向对象编程。...
java面向对象三要素封装继承和多态源码java面向对象三要素封装继承和多态源码java面向对象三要素封装继承和多态源码java面向对象三要素封装继承和多态源码java面向对象三要素封装继承和多态源码java面向对象三要素...
面向对象编程(Object-Oriented Programming,简称OOP)是一种重要...从简单的函数封装到复杂的类继承和多态,封装的层次逐渐提高,适应了不断变化的业务需求,这也是面向对象编程在现代软件工程中广泛应用的原因之一。
掌握类的封装特性、构造方法的定义、重载以及this和static关键字的使用 熟悉面向对象 的三大特征 掌握类与对象的创建和使用
面向对象编程(Object-Oriented Programming,OOP)是现代软件开发的基础之一,C#语言作为现代面向对象编程语言之一,封装(Encapsulation)是面向对象编程的四大基本特征之一。封装是指将对象的状态和行为封装在一...
教师资格证说课教案一,Java,面向对象之封装
总的来说,"Lua面向对象封装好的基类Class"为Lua开发者提供了一个方便的工具,使他们能够在不支持原生面向对象语法的环境中实现面向对象编程,从而更好地组织代码和设计复杂系统。通过理解和利用这类基类,开发者...
Lua的面向对象封装 LuaOO是Lua C API使用C++语言的面向对象封装。LuaOO是在lua原有的API基础之上扩展而来,极少地修改lua源码,主要是通过扩展lua原来的代码。扩展lua与C++环境交互。因此当有新版本的lua源码发布时...