Skip to content

Latest commit

 

History

History
85 lines (51 loc) · 5.83 KB

File metadata and controls

85 lines (51 loc) · 5.83 KB

8 重新组织数据

8.1 自封装字段

直接访问字段时, 字段之间越来越耦合, 此时应该用设/取值函数来包装字段, 提供访问字段的更复杂的功能, 并进一步优化子类访问字段时的能力. 一般来说为了方便可以先直接访问, 直到需要增加访问功能的时侯再使用设/取值函数.

要注意初始化途中最好少用设/取值函数, 防止语义混淆. 建议额外建立数据初始化函数. 处理数据项时, 最好让值对象是只读的, 也就是get函数返回副本, set函数创建新对象. 这样能防止用户使用的时侯出现一些引用别名问题

8.2 以对象取代数据值

当一些数据必须依赖于其它数据才有存在的意义(例如xyz坐标)时, 将这些数据进一步包装为数据对象减少耦合.

8.3 将值对象改为引用对象

8.1的Tips的进阶版, 主要是修改get的返回值令其返回引用. 当我们需要返回的一个应该同步改变且拷贝代价较大的对象时使用.

8.4 将引用对象改为值对象

8.3的反面, 对于那些很细小且不太应该同步改变的数据项返回内部不可变的一份拷贝, 在分布式系统中这种不可变对象比较常见因为不用太考虑同步问题. 也就是确保返回回来的值我们可以随意修改且不管什么用户在一个阶段内get的都是同一份值

8.5 以对象取代数组

简单的数组结构保存多个数据不够精准明了, 用对象包装这个数组并用设/取值函数作为入口, 然后将内部的数组写为private

8.6 复制"被观察数据"

主要是GUI编程会遇到的问题, 核心是观察者模式, 令GUI显示的代码与内部处理业务数据的代码分离开, 让GUI组件仅负责传递输入输出指令和结果, 后台业务代码负责真正的设值计算. 通常上也就是GUI类只有get, set和update函数, 后端业务代码处理算法逻辑, 然后额外建立一个领域类, 领域类中存放了用于计算的数据, GUI只保存用于显示的数据, 与领域类脱离. 后端结构处理领域类中的数据后, 调用update刷新显示GUI的数据.

8.7 将单向关联改为双向关联

当两个类都需要对方特性时, 繁复的get/set不够方便, 使用两个指针来直接操作对方数据. 通常关联有主次之分, 一对多的情况下, 那个一就是主, 负责更多的控制函数, 一对一或多对多时则无所谓.

8.8 将双向关联改为单向关联

8.7的反面, 主要是防止大量的引用导致的僵尸对象, 也就是某个对象已经死亡了但是由于主控制类对其的引用还存在所以始终不被清理. 方法是重新用设/取函数替代指针调用.

8.9 以字面值取代魔数

主要就是使用常量给魔数命名来提高代码的可读性

8.10 封装字段

也就是public转private

8.11 封装集合

有时候用户需要繁复的设/取值函数来控制目标类, 改为拷贝一个精简的副本(clone)打包供用户自己内部使用, 同时避免了用户始终在目标类上直接操作.

8.12 以数据类取代记录

通过数据类来分析记录类数组的元素并替代

8.13 以类取代类型码

如果类型码不会影响当前类的行为的话(例如仅用于一些常量函数), 用一个小小的类包装一下名称即可, 如果会影响当前类则应该考虑使用多态处理. 经过包装后的类型码主要是为了方便后续修改时的引用点查找, 提高代码的可读性而不是仅仅看着一堆不明所以的数字, 还适配了编译器的类型检查.

8.14 以子类取代类型码

8.13的进阶, 对于会影响目标类行为的类型码, 可以尝试用多态子类来处理, 用工厂函数包装和类型码有关的目标类, 然后返回不同的子类, 这样未来也方便进行扩展, 尽量保证与类型码相关的switch只出现在工厂函数中.

8.15 以状态/策略对象取代类型码

8.14的扩展, 对于无法经过多态处理优化的类型码场景, 例如某个对象携带的类型码自身在运行中会变化, 则应该使用状态/策略设计模式. 首先建立一个类并按照类型码用途进行命名, 这是状态对象. 然后为这个类添加对应各个类型码的子类, 然后在我们的目标类中保存这个类型码类, 增加对应的set函数, set函数会从工厂函数生成所需的类型码对象. 目标类后续的switch以这个类型码对象进行判断, 和8.13相似, 区主要是8.13的目标类不负责有关类型码的计算, 仅仅承载储存功能.

8.16 以字段取代子类

当很多子类之间的差别仅仅是返回的某个常量数据不同的时侯, 直接将这个常量数据字段放到基类中然后撤销这些子类, 因为仅有常量函数不同的子类没有足够的价值, 徒增复杂性而已.