Dependency injection DI、构造函数注入、模块、设计模式

Dependency injection DI、构造函数注入、模块、设计模式,dependency-injection,module,constructor-injection,Dependency Injection,Module,Constructor Injection,在我参与的项目中,我面临一些架构问题。该项目是一个ASP.NET MVC 2应用程序,它依赖于DI,尤其是Unity的构造函数注入。应用程序分为几个模块(每个模块是一组组件),向其他模块公开服务。这些服务在应用程序启动时注册到Unity。到现在为止没什么特别的。假设我有这个(每个模块都是一个用于简化的组件): 模a,模b ModuleA通过以下方法公开服务“IServiceA”: IServiceA(操作1-操作2-操作3) 来自ModuleB的ServiceB需要来自ModuleA的IServ

在我参与的项目中,我面临一些架构问题。该项目是一个ASP.NET MVC 2应用程序,它依赖于DI,尤其是Unity的构造函数注入。应用程序分为几个模块(每个模块是一组组件),向其他模块公开服务。这些服务在应用程序启动时注册到Unity。到现在为止没什么特别的。假设我有这个(每个模块都是一个用于简化的组件):

模a,模b

ModuleA通过以下方法公开服务“IServiceA”:

IServiceA(操作1-操作2-操作3)

来自ModuleB的ServiceB需要来自ModuleA的IServiceA,它通过构造函数注入(具体实现)获得它。然后它使用它

问题是当ModuleA被取消激活时(如果在应用程序启动时为当前用户激活了该模块,我们将在数据库中进行检查),因此serviceA未向Unity注册

然后在运行时出现异常,因为unity找不到IServiceA的注册,并且无法构造ServiceB。这是正常的

我想知道有一套模式或最佳实践来处理它。我的第一个想法是摆脱ServiceB的构造函数注入。但是,我应该使用对ServiceA的硬引用,我不喜欢它,或者使用更糟糕的ServiceLocator。我不想签入ModuleB,看看ServiceA是否可用,因为还有很多其他服务我会检查,并且应该处理纯基础设施的代码。如果serviceA可用或不可用,我希望ServiceB运行相同的代码(不知道是否可能)。我查看了网关模式,但不知道这是否可以帮助我

任何帮助都将不胜感激


谢谢,

您需要某种类型的默认实现,当ModuleA停用时可以接管。这个图案听起来很合身

只需先向Unity注册您的NullServiceA。这将是默认的IServiceA,除非被实际实现覆盖(我们称之为ConcreteServiceA)

对于更复杂的实现,您可以将NullServiceA和ConcreteServiceA封装在一个或另一种形式的中,根据可用性选择其中一种


例如,您可以让一个组合始终使用第一个(或最后一个)IServiceA实例注入其中。。。或者,选择标准可能基于某种元数据,确定模块是激活还是停用(听起来信息本身可以很好地融入假设的IModule界面)。

感谢您的回复。不幸的是,没有默认的实现。在应用程序的最初精神中,每个模块都应该“添加”新功能,但如果不可用,其他模块应该没有。现在所有模块都已连接,并且一个模块始终调用另一个模块。我考虑过实现一个空对象,但由于某些原因不知道它是否适合。如何处理操作1、操作2和操作3返回的数据?Dto应该是假的?如果操作4返回布尔值怎么办?我是否应该像实际服务返回该值那样处理它?无论何时定义接口,都要仔细考虑空对象实现的外观。如果你不能想出一个好的假设实现,那就是设计的味道。看看你是否能让设计更符合好莱坞的原则。返回void的方法总是可以有一个null实现。谢谢,这类似于将上下文传递给该方法并将其实现更改为null?是的,例如,不是传入基元参数,而是期望输出基元值,通常可以更改方法签名以接受某种命令对象或其他复杂类型,并将返回类型更改为void。然后,空对象实现可以简单地忽略输入。