关于《道法自然》一书中的“依赖倒置”问题

博客主要讨论编程中的依赖倒置原则,指出子系统应依赖接口,接口定义归属上层子系统。还强调上层模块和下层模块应共同依赖抽象接口,而非相互转换依赖关系。同时提到开闭、完全替换和依赖倒置原则源于‘针对接口编程’这一核心原则,属于OOD范畴。
《道法自然》一书问世后,有不少热心读者发来邮件探讨相关的技术问题。例如,前几天一位读者就“依赖倒置”原则来信指出了《道法自然》中的一个错误。在此,我向那位读者表示真诚的谢意,并将他的来信和王咏武的回复邮件贴在这里,供大家参考。


最近在书店里买到你们的新书《道法自然》。感觉写得非常好,正如李维先生的评价一样,内容丰富,汇集并组织大量的面向对象知识,并且以一个实践项目为主线将这些知识有机的组织,丰富而且有着内在的统一性。非常吸引人,我已经读了100多页。看得很仔细,也思考了很多,所以在读的过程中,我发现了一些小的错误或疑问,在此列出,与您商讨。
  p.9, line 2 : 一个排字错误:原意 -> 愿意
  p.140: 箭头应该是由class4 指向 class3, 友元类的依赖关系,我认为画反了。
  p.113, figure 6-3: 层间依赖关系, 这样的设计我认为不是很好,应该由数据持久化层依赖于 domain logic. 因为domain logic 才是问题域的本质与核心,才是最稳定的。所有的层都依赖于domain 层,domain 层才可以得到最优先的考虑。 这样也符合 Robert martin 在 《敏捷软件开发》中提出的 依赖倒置原则。 可以参考 《敏捷软件开发》 中文版的 page 256 以及chapter 11。也可参考《特征驱动开发方法》中文版的 page 156 的图。
  p.113, figure 6-4: 层依赖关系似乎也应该倒过来。道理和上一条是一样的。
  上面两条其实都是 Robert martin 所说的 DIP ( dependancy inversion principle). 它的含义是:
  • 子系统都只依赖于接口,这在你的书中已经提到。
  • 另一个含义,是将接口的定义归属到上层子系统中。也就是说,接口的变化,主要是由上层子系统的变化导致,受下层子系统的影响要小。 举例说, 就是domain 层拥有 domain 层和数据管理层的接口,而不是数据管理层拥有此接口。这中间的差别非常subtle, 但似乎也很重要。
  建议:建议将依赖倒置原则加入的您的书中。
  这些是我的个人看法,提出的目的是与您商讨。
  也许在这个点上,您是错的。但是瑕不掩瑜,我很庆幸自己买了一本好书。

        2004年10月20日



  多谢您的支持和鼓励,也非常感谢您中肯的意见。
  P.140关于友元类的描述,确实有一个明显的错误。其中图和代码如下所示:
  include “Class4.h”
  Class3
  {
    friend class class4;
    // ……
  };
  图和代码是统一的,没有错误,但是前面的文字有一个笔误:
  原文为:即Class3不仅依赖于Class4,而且Class3还是Class4的友元类。
  应该是:即Class4不仅依赖于Class3,而且Class4还是Class3的友元类(Class4希望能访问Class3的非公有成员)。

  关于依赖倒置原则,我在写《道法自然》时也经过了仔细的思考。下面从几个方面说明一下我的理解:
  首先,从理论上说,Robert Martin是这样定义的:依赖于抽象,而不要依赖于具象(参见:《道法自然 3.4.3)。
  更为详细的定义是:
  • 上层模块不应该依赖于下层模块,它们共同依赖于一个抽象。
  • 抽象不能依赖于具象,具象依赖于抽象。
  其次,以FishGUI为实例,从实践的角度来看。假设FishGUI框架系统必须要移植到不同的操作系统(如:Windows和Unix),为了使操作系统的变化不影响框架层,就必须抽象出一个操作系统适配器接口,FishGUI框架层中的类只依赖于该接口,而该接口的派生类具体实现到不同操作系统的调用。这个实现是符合依赖倒置原则的。如下图所示:
  如果我们认为适配器接口类属于框架层,由框架层的开发人员来设计,这个接口就会设计得很适合框架层的开发。但是容易遇到一个问题,当需要移植到另一个新的操作系统时,这个接口可能不适合该操作系统的实现,实现具体的适配器时非常麻烦。这时,两层的依赖关系如下图所示,下层依赖于上层。
  如果我们认为适配器接口属于适配层,由适配层的开发人员来开发,这个接口就会总结了多种操作系统的特性,使得移植非常方便。但是很容易造成框架层使用的困难。这时,两层的依赖关系如下图所示,上层依赖于下层。
  这两种不同的选择,在具体的设计中很容易遇到,两种设计得到的结果似乎是相反的,是一个两难的问题。
  最后,从传统的分层架构模式的要求来说,应该上层使用下层的服务,依赖于下层;而下层决不能使用上层的服务,依赖于上层。而且,从FishGUI的框架层和适配器层来说,确实,框架层会调用适配层,而适配层绝不会调用框架层,适配层仅仅是反向依赖于适配器接口。
  上面分析的这几点似乎存在着很大的矛盾。我觉得只要理解了下面的两个要点,就可以完美地把这些矛盾统一起来了。
  • 依赖倒置并不是把“上层依赖于下层”转变成“下层依赖于上层”(模块不可能毫无联系,总有一个模块被别人依赖,相互转换依赖关系没有任何意义),而是两者都依赖于一个抽象接口。
  • 开闭原则,完全替换原则和依赖倒置原则是对同一个核心原则从不同的视角观察得到的结果。这个核心原则就是我在《道法自然》一书中不断强调的“针对接口编程,而不要针对实现编程”。这些原则属于OOD的范畴,应该在OOD的阶段使用。
  根据这两个要点,我觉得对于上面FishGUI的例子,在架构分析阶段,把系统分为框架层和适配层时,不要考虑依赖倒置原则,而是从宏观上看,由于框架层要调用适配层,框架层依赖于适配层,上层依赖于下层。
  当进入面向对象设计阶段,这些OOD原则就能发挥作用了。这时,按照“针对接口编程,而不要针对实现编程”的原则,通过适配器接口的引入,就能很好地消除上层对于下层的依赖。这样的设计也就能很好地符合开闭原则,完全替换原则和依赖倒置原则,所以说,依赖倒置原则并不是真的把依赖反过来,而是解除了层之间的耦合,使它们更容易适应变化的需求。
  这时,也不需要强求加入的接口属于哪一层,而是应该由两层的设计人员共同协商解决,设计出对两层都方便的接口。

  这就是我在撰写《道法自然》一书时,对依赖倒置原则的一些思考,希望能听到你的想法。通过这样的交流,就能更加深我们对于OO原则的理解,使OO技术在实践中得到更好的应用,这也是我撰写《道法自然》一书最根本的想法。

  王咏武
  2004年10月25日

采用PyQt5框架与Python编程语言构建图信息管理平台 本项目基于Python编程环境,结合PyQt5图形界面开发库,设计实现了套完整的图信息管理解决方案。该系统主要面向图馆、店等机构的日常运营需求,通过模块化设计实现了图信息的标准化管理流程。 系统架构采用典型的三层设计模式,包含数据存储层、业务逻辑层和用户界面层。数据持久化方案支持SQLite轻量级数据库与MySQL企业级数据库的双重配置选项,通过统的数据库操作接口实现数据存取隔离。在数据建模方面,设计了包含图基本信息、读者档案、借阅记录等核心数据实体,各实体间通过主外键约束建立关联关系。 核心功能模块包含六大子系统: 1. 图编目管理:支持国际标准号、中国图馆分类法等专业元数据的规范化著录,提供批量导入与单条录入两种数据采集方式 2. 库存动态监控:实时追踪在架数量、借出状态、预约队列等流通指标,设置库存预警阈值自动提醒补货 3. 读者服务管理:建立完整的读者信用评价体系,记录借阅历史与违规行为,实施差异化借阅权限管理 4. 流通业务处理:涵盖借登记、归还处理、续借申请、逾期计算等标准业务流程,支持射频识别技术设备集成 5. 统计报表生成:按日/月/年周期自动生成流通统计、热门图排行、读者活跃度等多维度分析图表 6. 系统维护配置:提供用户权限分级管理、数据备份恢复、操作日志审计等管理功能 在技术实现层面,界面设计遵循Material Design设计规范,采用QSS样式表实现视觉定制化。通过信号槽机制实现前后端数据双向绑定,运用多线程处理技术保障界面响应流畅度。数据验证机制包含前端格式校验与后端业务规则双重保障,关键操作均设有二次确认流程。 该系统适用于中小型图管理场景,通过可扩展的插件架构支持功能模块的灵活组合。开发过程中特别注重代码的可维护性,采用面向对象编程范式实现高内聚低耦合的组件设计,为后续功能迭代奠定技术基础。 资源来源于网络分享,仅用于学习交流使用,请勿用于商业,如有侵权请联系我删除!
《基于SSM架构的学籍数据管理平台技术解析》 在当代数字化教育背景下,数据管理平台已成为教育机构运营的核心支撑。本系统以SSM技术组合为基础架构,构建了套完整的学籍信息处理体系,通过系统化的技术方案实现教育数据的规范化管理与智能分析。以下从架构设计、技术实现与功能模块三个维度展开说明。 、系统架构设计 该平台采用分层式架构设计,充分体现模块化与可维护性特征。Spring框架作为核心容器,通过依赖注入机制实现组件解耦;SpringMVC架构负责前端请求的路由与响应处理;MyBatis数据层框架则封装了数据库交互过程,通过映射配置简化SQL操作。三层架构协同工作,形成高内聚低耦合的技术体系。 二、技术实现要点 1. Spring容器:基于控制反转原则管理业务对象生命周期,结合面向切面编程实现事务控制与日志管理 2. SpringMVC模块:采用模型-视图-控制器设计范式,规范Web层开发流程,支持RESTful接口设计 3. MyBatis组件:通过XML配置实现对象关系映射,提供动态SQL生成机制,显著减少冗余编码 三、核心功能模块 1. 学籍信息维护:实现学员基本资料的增删改查操作,涵盖学籍编号、个人信息、所属院系等关键字段 2. 学业成绩管理:支持课程分数录入与批量处理,提供多维度统计分析功能 3. 教学组织管理:建立班级体系与学员关联关系,实现分级数据管理 4. 权限控制机制:基于角色访问控制模型,划分管理员、教职工、学员三级操作权限 5. 系统审计功能:完整记录用户操作轨迹,构建安全追踪体系 四、系统开发方法论 在项目生命周期中,采用结构化开发流程。前期通过需求调研确定系统边界,中期完成数据库范式设计与接口规范制定,后期采用迭代开发模式配合自动化测试,确保系统交付质量。 五、技术演进展望 当前系统虽未集成智能算法,但为未来升级预留了扩展接口。可预见的技术演进方向包括:基于学习行为数据的智能预警、个性化学习路径推荐等深度应用场景。 综上所述,该平台通过SSM技术体系实现了教育管理数据的标准化处理,既展示了现代软件开发范式的实践价值,也为教育信息化建设提供了可复用的技术方案。这种系统化的问题解决思路,充分体现了软件工程方法在教育领域的应用潜力。 资源来源于网络分享,仅用于学习交流使用,请勿用于商业,如有侵权请联系我删除!
评论 88
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值