09类与包

一、创建类的原因

1. 为现实世界中的对象建模

​ 为现实世界中的对象建模也许不是创建类的唯一理由,但它仍是个很好地理由!请为你程序中需要建模的每一个出现在现实世界中的对象类型创建一个类。把该对象所需要的数据添加到类里面,然后编写一些服务子程序来为对象的行为建模。

2. 为抽象的对象建模

​ 创建类的另一个合理的原因是要建立抽象对象的模型,所谓的抽象对象并不是一个现实世界中的具体对象,但它却能为另外一些具体的对象提供一种抽象。经典的 Shape(形状)就是一个很好地例子。Circle 和 Square 都是真实存在的,但 Shape 则是对其他具体形状的一种抽象。

​ 在程序设计中,抽象并不是像 Shape 一样现成就有的,因此我们必须努力工作以得出一些清晰的抽象。“从现实世界的实体中提炼出抽象的概念”这一过程是不确定的,不同的设计者会抽象出不同的共性来。

3. 降低复杂度

​ 创建类的一个最重要的理由便是降低程序的复杂度。创建一个类来把信息隐藏起来,这样你就无需再去考虑他们。当然,当你写到这个类的时候还是要考虑这些信息的。但类写好好,你就应该能够忘掉这些 细节,并能在无须来接其内部工作原理的情况下使用这个类。其他那些创建类的原因 —— 缩减代码空间、提高可维护性以及提高正确性 —— 都是很好地,但一旦失去了类的抽象能力,那么复杂的应用程序对于我们的智力而言将是无法管理的。

4. 隔离复杂度

​ 无论复杂度表现为何种形态 —— 复杂的算法、大型数据集、或错综复杂的通讯协议等 —— 都容易引发错误。一旦错误发生,只要它还在类的局部而未扩散到整个程序中,找到它就会比较容易。修正错误时引入的改动不会影响的其他代码,因为只有一个类需要下盖,不会碰到其他代码。如果你找到了一种更好、更简单或更可靠的算法,而原有的算法已经用类隔离起来的话,就可以很容易地把它替换掉。在开发过程中,这样做可以让你更容易地尝试更多设计方案,保留最好的一种方案。

5. 隐藏实现细节

​ 想把实现细节隐藏起来的这种愿望本身便是创建类的一个绝佳理由,无论实现细节是像访问数据库那般复杂,还是像决定用数值还是字符串来存储某个特定数据成员那般寻常。

6. 限制变动点的影响范围

​ 把容易变动的部分隔离开来,这样就能把变动所带来的影响限制在一个或少数几个类的范围内。把最容易变动的部分设计成最容易修改的。容易变动的部分有硬件依赖性、输入/输出、复杂数据类型、业务逻辑等。

7. 隐藏全局数据

​ 如果你需要用到全局数据,就可以把他的的实现细节隐藏到某个类的接口背后。与直接使用全局数据相比,通过访问器子程序来操作全局数据有很多好处。你可以改变数据结构而无须修改程序本身。你可以监视对这些数据的访问。“使用访问器子程序”的这条纪律还会促使你去思考有关数据是否就应该是全局的;经常你会豁然开朗地发现,“全局数据”原来这是对象的数据而已。

8. 让参数传递更顺畅

​ 如果你需要把一个参数在多个子程序之间传递,这有可能表明应该把这些子程序重构到一个类里,把这个参数当做对象数据共享。实质上,让参数传递得更顺畅并不是目标,但把大量的数据到处传递是在暗示换一种类的组织方式可能会更好。

9. 建立中心控制点

​ 在一个地方来控制一项任务是个好主意。控制可以表现为很多形式。了解一张表中记录的数目是一种形式;对文件、数据库连接、打印机设备进行的控制又是一种。用一个类来读写数据库则是集中控制的又一种形式。如果需要把数据库转换成平坦的文件或者内存数据,有关改动只会影响一个类。

​ 集中控制这一概念和信息隐蔽有些相似,但它具有独特的启发式功用,值得把它放到你的编程工具箱中。

10. 让代码更易于重用

​ 将代码放入精心分解的一组类中,比起把代码全部塞进某个更大类里面,前者更容易在其他 程序中重用。如果有一部分代码,它们只是在程序里的一个地方调用,只要它可以被理解为一个较大类的一部分,而且这部分代码可能会在其他程序中用到,就可以把它提出来形成一个单独的类。

11. 为程序族做计划

​ 如果你预计到某个程序会被修改,你可以把预计要被改动的部分放到单独的类中,同其他部分隔开,这是个好主意。之后你就可以只修改这个类或用新的类来取代它,而不会影响到程序的其余部分了。仔细考虑整个程序族的可能情况,而不单是考虑单一 程序的可能情况,这又是一种用于预先应对各种变化的强有力的启发式方法。

12. 把相关操作包装到一起

​ 即便你无法隐藏信息、共享数据或规划灵活性,你仍然可以把相关的操作合理地分组,比如分为三角函数、统计函数、字符串处理子程序、位操作子程序以及图像子程序等等。类时把相关操作组合在一起的一种方法。除此之外,根据你所使用的编程语言不同,你还可以使用包、命名空间或头文件等方法。

13. 实现某种特定的重构

​ 后面的章节“重构”中所描述的很多特定的重构方法都会生成新类,包括把一个类转换为两个、隐藏委托、去掉中间人以及引入扩展类等。为了更好地实现本节所描述的任何一个目标,这些都是产生各种新类的动机。

二、应该避免的类

1. 避免创建万能类

​ 要避免创建什么都知道、什么都能干的万能类。如果一个类把功夫豆花在用 Get() 方法和 Set() 方法向其他类索要数据(也就是说,深入到其他类的工作中并告诉他们该如何做)的话,请考虑是否应该把这些功能组织到其他那些类中去,而不要放到万能类里。

2. 消除无关紧要的类

​ 如果一个类只包含数据但不包含行为的haul,应该问问自己,它真的是一个类吗?同时应该考虑把这个类降级,让他的数据成员成为一个或多个其他类的属性。

3. 避免用动词命名的类

​ 只有行为没有数据的类往往不是一个真正的类。请考虑把类似 DatabaseInitialization 或 StringBuilder 这样的类变成其他类的一个子程序。

三、超越类:包

​ 类时当前程序员们实现模块化的最佳方式。不过模块化是个很庞大的话题,其影响范围要远远超出类。在过去几十年间,软件开发的进展在很大程度上要归功于我们在编程时进行工作粒度的增长。首先是语句,这在当时算得上是自机器指令以来迈进的一大步。接下来就是子程序,再后来则是类。

​ 很显然,如果我们能有更好的工具把对象聚合起来,我们就可能更好地朝着抽象和封装的目标迈进。

posted @ 2018-11-06 22:00  洛克十年  阅读(146)  评论(0编辑  收藏  举报