第7章 封装
分解模块时最重要的标准是,识别出那些模块应该对外界隐藏的细节。
类是为隐藏信息而生的。
除了类的内部细节,使用隐藏委托关系来隐藏类之间的关联关系通常也很有帮助(反向注入)。
类与模块已然是施行封装的最大实体了,但小一点的函数对于封装实现细节也有所裨益。
封装记录
以数据类取代记录(Replace Record with Data Class)
记录型结构能直观地组织起存在关联的数据,可以将数据作为有意义的单元传递,而不仅是一堆数据的拼凑。
封装集合
对程序中的可变数据进行封装,这样很容易看清楚数据被修改的地点和修改方式。
封装集合时如果让取值函数返回集合本身,则将集合的修改也扩散到了所有使用它的地方。应该通过”添加“和”移除“方法,来让集合的修改必须通过类。
依赖于别人的好习惯是不明智的。不要让集合的取值函数返回原始集合,避免客户端的意外修改。
以对象取代基本类型
将数据包装成类,后续添加的业务逻辑则可以封装进去。数据被使用的越多,包装成类对代码库的影响就更深远。
以查询取代临时变量
临时变量允许我们使用之前的值,还能解释它的含义,避免重复计算,但值得更进一步,抽取成查询函数。
将变量的计算逻辑放到函数中,也有助于在函数之间设立清晰的边界,这可以帮助我们发现并避免难缠的依赖及副作用。
提炼类
一个类应该只是一个清晰的抽象,只处理一些明确的责任。但类会不断随着业务逻辑扩展,当责任不断增加,此时就需要考虑将类分离出去。
如果某些特性只影响类的部分特性,或者某些特性需要以另一种方式子类化,这就意味着你需要分解原来的类。
内联类
如果一个类不在承担足够责任,不再有单独存在的理由,通常可以将其内联到另一个类中。
隐藏委托关系
封装是一个好的模块化设计的最关键特征之一。封装意味着每个模块都应该尽可能少地了解系统的其他部分。
有更多值得封装的东西,比如客户端调用的服务,可以将委托关系隐藏起来,及时将来委托关系发生变化,也只会影响服务对象,而不会直接波及所有客户端。
移除中间人
移除中间人是隐藏委托关系的反向重构,当需要委托的特性越来越多时,更多的转发函数会使人烦躁。这个时候可以通过移除中间人,让客户端直接调用服务。
重构的意义就在于:你永远不必说对不起——只需要把出问题的地方修补好就行了。
替换算法
用简单清晰的方式取代复杂的方式。
替换一个巨大且复杂的算法是非常困难的,需要先将它分解为简单的小型函数。