知识卡片

加密程序案例:源码依赖方向应与数据流向脱钩,让低层成为高层的插件

结构图卡

内容

用[[层次按距离输入输出的远近定义高层策略变更应更少更重大]]分析一个简单加密程序:从输入设备读字符、用查表法转换、把转换后的字符写到输出设备——数据流向是”读→翻译→写”,而Translate组件因为距系统输入输出最远,是层次最高的组件。数据流向和源码依赖关系不总是同一方向,这正是架构设计工作的核心之一:我们希望源码依赖与数据流向脱钩、只与组件层次挂钩。如果直接把程序写成encrypt() { while(true) writeChar(translate(readChar())) },看起来简洁直白,实则是一个错误的架构——它让高层组件里的encrypt()函数直接依赖了低层组件的readChar()writeChar()函数,违背了”低层依赖高层”的准则。更好的设计是把Encrypt类连同它需要的CharReaderCharWriter两个接口一起框进边界内,所有依赖关系都指向这个边界内部,这样Encrypt就成了系统里最高层的组件;而ConsoleReaderConsoleWriter这些具体类因为直接对接输入输出,属于低层组件,反过来依赖Encrypt定义的接口。这样一来,高层的加密策略和低层的输入输出策略被彻底解耦——I/O部分的策略变更不太可能影响加密策略:加密算法本身发生变更的概率远小于I/O设备发生变更的概率,即便加密算法真要变,原因也往往比I/O设备的变更更重大。从组件关系上看,这就是”低层组件应该成为高层组件的插件”:Encryption组件对IODevices组件一无所知,反过来IODevices组件依赖Encryption组件——本章讨论的策略分层实践,正是SRP、OCP、CCP、DIP、SDP、SAP这些原则在具体场景下的综合应用。

结构图

flowchart LR
    subgraph 错误架构
    Encrypt_bad[encrypt高层函数] -->|直接依赖,违反层次准则| ReadChar[readChar 低层]
    Encrypt_bad --> WriteChar[writeChar 低层]
    end
    subgraph 正确架构
    ConsoleReader[ConsoleReader 低层具体类] -.实现.-> CharReader[CharReader接口]
    ConsoleWriter[ConsoleWriter 低层具体类] -.实现.-> CharWriter[CharWriter接口]
    Encrypt[Encrypt 最高层组件] --> CharReader
    Encrypt --> CharWriter
    end

参考来源

- 位置:《架构整洁之道》第19章《策略与层次》"层次""本章小结"(源文件:_epub-src/text/part0014_split_004.html) - 结论依据:原文对比错误架构(encrypt直接依赖readChar/writeChar)与正确架构(Encrypt类通过CharReader/CharWriter接口反转对ConsoleReader/ConsoleWriter的依赖),说明这样能让高层加密策略与低层I/O策略解耦,并将低层组件定位为高层组件的插件,直接支撑本卡片的结构图与解释。 - 原始内容:这个程序架构设计的错误在于,它让高层组件中的函数encrypt()依赖于低层组件中的函数readChar()与writeChar()……这个架构将高层的加密策略与低层的输入/输出策略解耦了……低层组件应该成为高层组件的插件。