封装
一、封装记录(记录封装成类)
- 记录型结构可以有两种类型:
- 第一种需要声明合法的字段名字比如{start: 1, end: 5},C#中没有这种特性。
- 第二种是语言库本身实现的,比如hash、map、dictionary等。使用这种记录的缺陷在于,一条记录持有什么字段往往不够直观,只能查看它的创建点和使用点。
- 这条建议是对于可变数据,对于不可变数据可以将它保留为记录。
- 重点在于将更新函数放在类中。
- 读取操作的处理
- 把所有对数据的读取提炼成函数,并将它们搬移到类中。
- 优点提供了清晰的API列表;
- 缺点代码量激增;
- 返回原始数据的一份副本:
- 性能问题、无法修改原数据
- 对每个字段进行循环封装:
- 工作量庞大
- 把所有对数据的读取提炼成函数,并将它们搬移到类中。
二、封装集合
-
简单理解,封装集合就是将程序中的可变集合数据集(List等),封装到类中。这样在需要更改数据结构时就非常方便。但在封装集合时,有一个常见的错误,让取值函数返回集合本身。这使得集合成员变量可以直接被修改,而封装它的类全然不知。有三种方法可以到达封装的目的:
- 永远不直接返回集合的值,通过定义类上的方法来替代。
2. 以某种形式限制集合的访问权,只允许对访问的集合进行读操作。比如java中的只读代理。
3. 返回集合的副本。
- 永远不直接返回集合的值,通过定义类上的方法来替代。
-
作者推荐的做法是:
- 定义单独的添加和移除方法,这样通常就不需要Set设值函数了。如果还是需要设置方法API,要确保用一份副本给字段赋值。
- Get取值函数,返回数据的副本。
三、以对象取代基本类型
- 开发初期,往往决定以简单的基本类型表示数据。但是只要发现数据的操作不仅仅局限于打印时,就该为它创建一个新类。
- 为新的对象添加构造函数,和各种操作函数。
四、以查询取代临时变量
- 有助于分解冗长的函数,在分解过程中不再需要将变量作为参数传递给提炼出来的小函数;这里的查询是类似为C#中的属性。
- 这类重构手法在类中施展效果最好,因为类为待提炼函数提供了一个共同的上下文。
- 注意这种手法,只适用于每次计算都得到相同值的变量,即变量是只读的。
五、提炼类
- 如果某些数据和某些函数总是一起出现,某些数据经常同时变化甚至彼此相依,就表示你应该将它们分离出去。
- 另一个在开发后期出现的信号是类的子类化方式。如果发现子类化只影响类的部分特性,那么在基类和子类不变的部分,需要分离出成为一个组件。
六、 内联类
- 提炼类的反向重构,不再赘述
七、 隐藏委托关系
-
在服务对象上安置一个简单的委托函数。调用者通过委托函数来访问服务对象内的组件。这样的好处是,当未来委托关系发生变化,变化也只影响服务对象,而不会直接波及所有客户端。
//原代码// var manager = aPerson.department.manager; //新代码// var manager = aPerson.manager; class Person { Manager manager { get{return this.department.manager;} } }
八、移除中间人
- 当受委托的特性功能越来越多,更多的转发函数就会使人烦躁;
九、替换算法
- 如标题。用简单的算法替代复杂的算法。