设计讨论:依赖倒置,与 “I'll call you”

问题来自于我和同事在一个跨系统交互设计上的分歧。

同事的设计,基本上是这样的:

这种设计很常见,其基本思路就是:服务端接口需要什么数据,客户端就传入什么数据。这种设计的优点在于简单:开发简单,交互简单。但是它的缺点也很明显:扩展性低。一旦服务端对某个业务中的业务-数据依赖关心进行了修改,则客户端很可能也要跟着修改。例如,如果系统B中,完成业务B1需要的数据不再是D1而是D3,则不光系统B要改,系统A也要改。如果还有系统C/D/E/F也调用了这个接口,那么这些系统都面临着修改代码的风险。

实际上,不仅仅是系统间的服务,在系统内部服务的设计上,这种思路也很常见。我曾经见过一个用作金额计算的类。它的计算公式是a+b/c-d^e,而它对外暴露的方法居然就是public BigDecimal calculate(BigDecimal a, BigDecimal b, BigDecimal c, BigDecimal d, BigDecimal e)。当公式需要扩展为a+b/c-d^e-f时,其中的麻烦可想而知。

造成这种风险、麻烦的原因就在于:这个设计不仅简单的实现了客户端对服务端的业务依赖,而且将服务端内部的控制依赖也暴露、延伸到了客户端。

客户端对服务端的依赖,是一种业务上的“正向”依赖。没有服务端提供的服务,客户端的业务也无法正常的进行下去。

但是,我们在做设计的时候,不应当简单的临摹业务流程。业务流程从A到B,系统设计就画两个方框+一个箭头;这是在为现在的自己偷懒。更不应当把业务流程中的依赖关系过度的延伸出去;这简直是在为三个月后的自己挖坟。

对这一个系统的设计,我的观点就是:系统B把业务-数据间的依赖关系全部收到自己的系统中去。如下图。

即,客户端在调用时,提供一个数据主键。服务端根据自己的业务需要,按主键去查询出所需的数据。

这样做的缺点是复杂。代码会复杂,交互也更复杂。由于多了一次交互,性能上会有下降。另外在分布式事务方面还有一点小隐患。

但是这样的优点,恰恰就是易于扩展。只要新业务所需数据仍然落在数据集合D内,那么系统A无需任何改动。

带来这个优点的,就是依赖倒置。虽然在业务上,是客户端依赖于服务端的功能;但是在设计上,是服务端依赖于客户端的数据。并且,这种依赖只是简单的数据依赖。这也是所谓的“好莱坞法则”:Don‘t call me, I‘ll call you!

实际上,同事的设计和我的设计,在我们的系统中都已经有了实践。到目前为止的结果,是按同事的思路设计的另一个系统服务已经经过了二次改造,归入我的思路中了。而按我的思路设计的另一个系统服务,目前在做性能上的优化。

遗憾的是,我没有说服他。他仍然坚持己见,只是在客户端调用接口时,将数据集合D一次性提交到服务端。

这种思路算一个折中。但是,如果服务端所需数据集超过了数据D呢?按他的方案,客户端仍然需要修改;按我的方案,在客户端没有开通对应的查询接口时也需要修改。只不过,客户端是我负责的系统(也许这也是我一直跟他争执的原因之一吧),而这个系统中,已经规划了“每个资源都应有查询服务”。

附,分布式事务上的一点小隐患在于:如果在客户端调用服务端的那个事务中,主键key所对应的数据有部分还未提交,那么,通过查询接口是无法查询到这部分数据的。弥补措施是在服务接口中把这一部分数据传过来,作为“优先”配置或数据,覆盖查询接口中查到的结果。

设计讨论:依赖倒置,与 “I'll call you”

时间: 2024-11-03 22:10:13

设计讨论:依赖倒置,与 “I'll call you”的相关文章

架构设计之依赖倒置、控制反转与依赖注入

名词解释 依赖:一种模型元素之间的关系的描述.例如类A调用了类B,那么我们说类A依赖于类B. 耦合:一种模型元素之间的关系的描述.例如类A调用了类B或类B调用了类A,那么我们说类A与类B有耦合关系. 耦合度:模型元素之间的依赖程度的量化描述. 控制:一种模型元素之间的关系的描述.例如类A调用了类B,那么我们说类A控制类B. 绪论 架构设计的对象一般是类库.框架和应用程序.其工作任务除了类库.框架.应用程序各个模块(类)之间的关系设计之外,还包括类库.框架和应用程序三者之间关系的设计.而依赖倒置.

五大设计原则------依赖倒置

依赖倒置原则的定义: 高层模块不应该依赖你低层模块,两者都应该依赖其抽象.    抽象不应该依赖细节.    细节应该依赖抽象. 抽象就是指接口或抽象类,两者都是不能被直接实例化的.细节就是实现类,实现接口或继承抽象类而产生的类就是绿茸茸,其特点就是可以直接被实例化.也就是可以加上一个关键字 new 产生一个对象 更精简的定义就是” 面向接口编程“ OOD (Object Oriented Design, 面向对象设计) 的精髓之一. 采用依赖倒置原则可以减少类间的耦合性,提高系统的稳定性,降低

Java设计原则—依赖倒置原则(转)

依赖倒置原则(Dependence Inversion Principle,DIP)的原始定义: 高层模块不应该依赖底层模块,两者都应该依赖其抽象: 抽象不应该依赖细节: 细节应该依赖抽象. 依赖倒置原则在Java语言中的表现是: 模块间的依赖通过抽象发生,实现类之间不发生直接的依赖关系,其依赖关系是通过接口或者抽象类产生的: 接口或抽象类不依赖于实现类: 实现类依赖接口或抽象类. 依赖倒置原则实际上就是要求"面向接口编程". 采用依赖倒置原则可以减少类间的耦合性,提高系统的稳定性,降

设计模式.设计原则-依赖倒置原则

1:依赖倒置原则在Java语言中的表现就是: 模块间的依赖通过抽象发生,实现类之间不发生直接的依赖关系,其依赖关系是通过接口或抽象类产生的.接口或抽象类不依赖于实现类.实现类依赖与接口或抽象类. 采用依赖倒置原则可以减少类间的耦合性,提高系统的稳定性,降低并发开发引起的风险,提高代码的可读性和可维护性.依赖是可以传递的.只要做到抽象依赖,即使是多层的依赖传递也无所畏惧. 对象的依赖关系又三种方式来传递:1:构造函数传递依赖对象2:Setter方法传递依赖对象 3:接口声明依赖对象 2:最佳实践:

深入理解JavaScript系列(22):S.O.L.I.D五大原则之依赖倒置原则DIP

前言 本章我们要讲解的是S.O.L.I.D五大原则JavaScript语言实现的第5篇,依赖倒置原则LSP(The Dependency Inversion Principle ). 英文原文:http://freshbrewedcode.com/derekgreer/2012/01/22/solid-javascript-the-dependency-inversion-principle/ 依赖倒置原则 依赖倒置原则的描述是: A. High-level modules should not

[Unity 设计模式]IOC依赖倒置

1.前言 最近在看<游戏开发与设计模式>一书,看到控制反转设计模式,作者说:上层模块不应该依赖于下层模块,上层模块和下层模块都应该依赖于接口,这样能减少耦合.然后附带举了个例子,我觉得特别好,就是一台计算机是属于上层模块,里面硬盘属于下层模块,计算机依赖于硬盘,硬盘是计算机的基本组成部件之一.这里提到依赖一词,下面就详细谈谈依赖. 2.依赖 依赖就是一种联系关系,人对人的依赖那是一种羁绊关系.再拿上面的计算机举例,华硕是我们都耳熟能详的计算机厂商,西部数据和希捷都是硬盘厂商,如果说华硕依赖于某

依赖、依赖倒置、控制反转、依赖注入

1.依赖 依赖就是有联系,有地方使用到它就是有依赖它,一个系统不可能完全避免依赖.如果你的一个类或者模块在项目中没有用到它,恭喜你,可以从项目中剔除它或者排除它了,因为没有一个地方会依赖它.下面看一个简单的示例: /// <summary> /// 用户播放媒体文件 /// </summary> public class OperationMain { public void PlayMedia() { MediaFile _mtype = new MediaFile(); Pla

IoC模式(依赖、依赖倒置、依赖注入、控制反转)

1.依赖 依赖就是有联系,有地方使用到它就是有依赖它,一个系统不可能完全避免依赖.如果你的一个类或者模块在项目中没有用到它,恭喜你,可以从项目中剔除它或者排除它了,因为没有一个地方会依赖它.下面看一个简单的示例: /// <summary> /// 用户播放媒体文件 /// </summary> public class OperationMain { public void PlayMedia() { MediaFile _mtype = new MediaFile(); Pla

依赖倒置原则(DIP)

1. 定义 (1)高层模块不应依赖于低层模块,两者都应该依赖于抽象.(2)抽象不应该依赖于细节,细节应该依赖于抽象. 为什么是“倒置”这个词? 这是由于许多传统的软件开发方法,比如结构化分析和设计,总是倾向于创建一些高层依赖于低层模块.策略依赖于细节的软件结构.实际上这些方法的目的之一就是要定义程序层次结构,该层次结构描述了高层模块怎样调用低层模块.一个设计良好的面向对象的程序,其依赖于程序结构相对于传统的过程式方法设计的通常结构而言就是被“倒置”了. 高层模块包含了一个应用程序中的重要的策略选