当使用依赖反转原则(DIP)时,我想知道如何使底层代码可重用。
在罗伯特·C·马丁(RobertC.Martin)的“清洁架构”()一书中,DIP是这样描述的:高级组件定义它们需要的接口,然后底层组件实现这些接口,如
+-----------------------------------+
| |
| Application ------> Service <I> |
| ^ |
+-------------------------|---------+
|
+----|--------+
| ServiceImpl |
+-------------+
那样的话
ServiceImpl
的源。也许我头脑中的图像是错误的,但我总是认为上面的图片中的Service
可能类似于日志服务,所以接口可能有debug()
、info()
等方法,然后实现可以登录到文件、数据库或其他任何东西。
我发现这种方法有两件事有点奇怪:
ServiceImpl
中的通用日志代码不知道它正在记录的数据,需要从大的有价值的应用程序模块中导入一个接口,对吗?在我的低级代码中,我有一个看起来像from high_level_app import ServiceInterface
的行,感觉不太对。这感觉就像我在这里创造了一个对更高层次模块的人为依赖。所以我想问:
发布于 2020-01-27 04:36:12
那张照片漏掉了一些细节。Service
接口不是一个通用接口;相反,它有专门针对应用程序需求的方法。现在,以这种方式使用DI的思想是,您希望能够独立地更改甚至完全替换服务的实现。单独打包的ServiceImpl
本质上是应用程序的插件。
要真正实现该服务,您可能要使用一些通用的第三方库。这个第三方库是可重用的,它解决了一个特定的问题,这个问题在不同的领域在一种或另一种形式上是相当常见的。当然,它不知道您的应用程序,它当然不依赖于它。
那么如何应用DI呢?
您将引入一个包装器/适配器--一个您拥有的组件,它将这个第三方组件适应应用程序所需的Service
接口。
然后这个包装器实现了接口,但是在幕后,它调用可重用的通用库。
因此,依赖结构如下:
|---------------- 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时,我将如何创建可重用的低级组件,而不只是使它们在我现在处理的特定的高级组件中可用呢?
通常需要一些时间和几个项目才能真正获得足够有价值的代码,以便将其分离成一个可重用的组件,但是通常,您会识别可重用的部分(必要时对它们进行概括,进行一些重构、代码清理等),并按照上面描述的方式将它们分离出来。
发布于 2020-01-28 18:56:01
罗伯特·马丁( Robert )提出的六边形体系结构也被称为“端口和适配器”,这是有原因的。
高级接口的低级别实现通常是从应用程序需求(高级别策略)到具体基础结构的(非常简单的)适配器。
如果这些适配器变得复杂,我建议将所有泛型逻辑分解到函数和类中。这些函数和类最终将不依赖于com.myapp
包(例如。接口等)和瞧:您创建了通用的可重用代码,这些代码可以转到下一个项目或其他适配器。
发布于 2020-01-27 05:20:56
如果您使用日志记录作为示例,那么是的,如果它是严格按照您的方式实现的,则可以这样描述DIP。但我认为有两类基础设施问题。日志记录、配置和数值都是已经解决的问题的例子,很少像您所描述的那样需要DIP。但是当涉及到实际的应用逻辑和行为时,严格的DIP对于将高层策略和低级实现细节分开,提供更好的可测试性和模块化是非常有价值的。
https://softwareengineering.stackexchange.com/questions/404313
复制相似问题