首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >依赖反转原理与底层代码重用

依赖反转原理与底层代码重用
EN

Software Engineering用户
提问于 2020-01-27 01:46:11
回答 3查看 392关注 0票数 1

当使用依赖反转原则(DIP)时,我想知道如何使底层代码可重用。

在罗伯特·C·马丁(RobertC.Martin)的“清洁架构”()一书中,DIP是这样描述的:高级组件定义它们需要的接口,然后底层组件实现这些接口,如

代码语言:javascript
运行
复制
+-----------------------------------+
|                                   |
|  Application ------> Service <I>  |
|                         ^         |
+-------------------------|---------+
                          |
                     +----|--------+
                     | ServiceImpl |
                     +-------------+

那样的话

  • 应用程序代码不受低级组件更改的影响。
  • 应用程序不依赖于ServiceImpl的源。
  • “源代码依赖与控制流相反”。

也许我头脑中的图像是错误的,但我总是认为上面的图片中的Service可能类似于日志服务,所以接口可能有debug()info()等方法,然后实现可以登录到文件、数据库或其他任何东西。

我发现这种方法有两件事有点奇怪:

  1. ServiceImpl中的通用日志代码不知道它正在记录的数据,需要从大的有价值的应用程序模块中导入一个接口,对吗?在我的低级代码中,我有一个看起来像from high_level_app import ServiceInterface的行,感觉不太对。这感觉就像我在这里创造了一个对更高层次模块的人为依赖。
  2. 从更语义的角度来看,很明显,我的低级别日志实现中的功能可以在整个组织中重用,但是由于更高级别的代码定义了接口,而且(如上所述)我可能有一个源代码依赖于更高级别的代码,这会限制重用吗?

所以我想问:

  • 依赖反转原则是否普遍地抑制了底层库的重用?或者我的日志记录服务有缺陷,因为这不是DIP的目标吗?
  • 在使用DIP时,我将如何创建可重用的低级组件,而不只是使它们在我现在处理的特定的高级组件中可用呢?
EN

回答 3

Software Engineering用户

回答已采纳

发布于 2020-01-27 04:36:12

那张照片漏掉了一些细节。Service接口不是一个通用接口;相反,它有专门针对应用程序需求的方法。现在,以这种方式使用DI的思想是,您希望能够独立地更改甚至完全替换服务的实现。单独打包的ServiceImpl本质上是应用程序的插件。

要真正实现该服务,您可能要使用一些通用的第三方库。这个第三方库是可重用的,它解决了一个特定的问题,这个问题在不同的领域在一种或另一种形式上是相当常见的。当然,它不知道您的应用程序,它当然不依赖于它。

那么如何应用DI呢?

您将引入一个包装器/适配器--一个您拥有的组件,它将这个第三方组件适应应用程序所需的Service接口。

然后这个包装器实现了接口,但是在幕后,它调用可重用的通用库。

因此,依赖结构如下:

代码语言:javascript
运行
复制
|---------------- code you own (your application) -------|----- frameworks/libs -----|
|------ core application --------|-- gateways/adapters --|                           |

[Application]----->[Service]<|--------[Wrapper]----------->[Reusable Generic Library]

Wrapper通过调用和编排可重用库的几个通用操作来实现特定于用例的服务(例如,支持用例特定需求的操作)。现在,日志记录可能不是最好的例子,因为它主要是一个横切的关注点,但是假设为了业务目的需要保持一个审计日志;那么,Service接口上的日志方法将被表示为领域概念,例如LogCustomerInfo,并且可能采用表示域元素(例如Customer对象)的参数。将其与通用库进行比较:它有像LogInfo(string)LogWarning(string)这样的方法。

依赖反转原则是否普遍地抑制了底层库的重用?

如你所见,答案是否定的。底层库实际上是它自己的东西;这里应用的DI只是提供了一种机制,将应用程序与低级库从结构上隔离开来。

如果低级通用库是您自己的,而不是第三方库,那么它的代码就不会进入Wrapper,因为它不能依赖或不知道您的应用程序(您基本上做出了与第三方供应商相同的决定)。

在使用DIP时,我将如何创建可重用的低级组件,而不只是使它们在我现在处理的特定的高级组件中可用呢?

通常需要一些时间和几个项目才能真正获得足够有价值的代码,以便将其分离成一个可重用的组件,但是通常,您会识别可重用的部分(必要时对它们进行概括,进行一些重构、代码清理等),并按照上面描述的方式将它们分离出来。

票数 3
EN

Software Engineering用户

发布于 2020-01-28 18:56:01

罗伯特·马丁( Robert )提出的六边形体系结构也被称为“端口和适配器”,这是有原因的。

高级接口的低级别实现通常是从应用程序需求(高级别策略)到具体基础结构的(非常简单的)适配器。

如果这些适配器变得复杂,我建议将所有泛型逻辑分解到函数和类中。这些函数和类最终将不依赖于com.myapp包(例如。接口等)和瞧:您创建了通用的可重用代码,这些代码可以转到下一个项目或其他适配器。

票数 1
EN

Software Engineering用户

发布于 2020-01-27 05:20:56

如果您使用日志记录作为示例,那么是的,如果它是严格按照您的方式实现的,则可以这样描述DIP。但我认为有两类基础设施问题。日志记录、配置和数值都是已经解决的问题的例子,很少像您所描述的那样需要DIP。但是当涉及到实际的应用逻辑和行为时,严格的DIP对于将高层策略和低级实现细节分开,提供更好的可测试性和模块化是非常有价值的。

票数 0
EN
页面原文内容由Software Engineering提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://softwareengineering.stackexchange.com/questions/404313

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档