• A Philosophy of Software Design读书笔记——分or合


    软件设计中有个很重要的问题:两个功能,是分成两部分实现,还是合在一部分实现呢

    合or分的目的是减少系统复杂度,但是拆分有带来一些复杂度,比如:

    1、组件个数增加复杂性,难以追踪每个组件,同时接口也变多

    2、模块会变多,对于类来说,需要分别考虑他们的生命周期等

    3、相邻的部分可能分散在不同的组件中,开发者很难同时意识到他们的存在,增加学习成本

    4、分解可能带来重复

    如果两个功能是紧密相关的,最好把他们放到一个组件中,如果是不相干的,可以把他们拆开实现。哪些表现为相关呢:

    1、需要依赖相同的信息

    2、他们一般都是被同时使用,一个功能被使用时,另一个功能也被调用

    3、两个功能相关联,被一个更高层次的模块一起包含

    4、但看一个功能的代码难以理解,必须看另一个功能的代码

    本章主要介绍如何合并or拆分代码功能块

    如果共享信息,那么要合并模块

    在httpserver的例子中,读取和解析socket,这两个模块都需要感知http协议的格式,那么需要合并在同一个模块实现,而不是拆分。

    如果能简化接口,那么要合并模块

    如果两个模块合并后,对外提供的接口更简单了,同时实现起来也更简单了。这通常发生在两个模块时为了解决一个问题的不同部分。

    如果能减少重复,那么要合并模块

    如果发现代码在多处重复,那么需要合并。

    一种方式是把重复的代码抽象成一个函数,这种方式比较适合于重复的代码比较长,如果重复的代码很短,比如就2、3行,那么就不需要抽象,而且抽象成函数时,如果参数较长(经常发生这种情况),那么也不需要抽象。

    另一种方式进行重构,然后将重复的代码在一处执行,比如C++中的RAII机制来清理现场

    分离专用模块的代码和通用模块的代码

    如果一个模块可以实现多种功能,那么就要被抽象为一个通用的机制,而不应该包含哪些专用的代码,也不应该包含其他通用代码(单一职责原则)。一个好的方式是,专用模块通过接口形式提供出来,然后在实现专用模块时,用上通用模块。

    一般情况下,越底层,代码应该越通用,越顶层,代码应该越专用,所以,拆分通用模块和专用模块的方式是抽象底层为通用模块,上层为专用模块提供接口

    拆分or合并方法

    方法太长,会不易懂,所以业界一般建议拆分过长的方法,比如“超过20行的方法就应该拆解”,但是作者认为根据方法行数来判断是否拆分方法是不客观的,方法太多意味着接口太多,会增加复杂度,如果一个方法的各个部分相关联,那么拆分之后,各个子方法更加难读,是否拆分方法还是看是否能够简化复杂度。

    在设计方法时,最重要的是提供简单清晰的抽象,每个方法制作一件事而且要把这件事做干净,接口要简单,实现要深,这样的方法就是好方法,而不是看方法的代码行数。

    那么什么时候拆分方法呢?能够简化抽象,比如下面这种方法拆分,a是好的;如果要拆分,可以把通用模块抽象成子方法,如b所示,这个子方法在其他模块也可以用到,但是如果在阅读代码的时候,如果为了理解方法,需要在子方法和父方法之间来回跳转,那么这种就没必要拆分;c勉强可以,如果拆分成的两个字方法之间基本没有关联,使得接口更加清晰,而且拆分之后,两个子方法的接口比原来方法的接口更加简单清晰,但是如果每次实现该功能的时候,调用都要同时调用这两个方法,那么拆分没必要;d是错误的拆分方法

     

  • 相关阅读:
    天津工业大学计算机考研资料汇总
    DC/DC开关电源学习笔记(十)Buck降压电路仿真及工程应用实例
    PWN利器-pwntools安装、调试教程一览
    云视频协作平台有哪些 云视频在线审片解决方法
    spirngcloud的基本介绍与服务注册
    js每日十题
    为什么要使用双重校验锁来实现单例模式?
    发布 VectorTraits v1.0,它是 C# 下增强SIMD向量运算的类库
    读《Shape-Guided: Shape-Guided Dual-Memory Learning for 3D Anomaly Detection》
    API安全实战
  • 原文地址:https://blog.csdn.net/yh88623131/article/details/127895722