【问题标题】:How to understand the rule: "Store in IoC container only services. Do not store any entities."如何理解规则:“仅在 IoC 容器中存储服务。不要存储任何实体。”
【发布时间】:2011-08-24 01:58:15
【问题描述】:

规则“仅在 IoC 容器中存储服务。不要存储任何实体。”我在那个blog 中找到了它,它有很多支持者。

还有类构造函数的示例:

    MyClass(ILog log, 
            IAudit audit, 
            IPermissions permissions, 
            IApplicationSettings settings) {/*..*/}

其中 MyClass 被宣布为不应存储在容器中的实体。

所以“IoC 就绪服务”不能依赖于基础设施......服务。

但现在我完全不明白“IoC 人”如何使用“真实代码”。 C#中的Service仍然会作为一个类来开发,并且该类通常依赖于封装日志的类,很少依赖于封装自定义异常处理的类(例如将未处理的异常转换为FaultContract)等......

我看到了一些方法: 可能他们只是没有声明那些基础设施依赖项?将它们用作静态方法中可用的功能?

或者可能是“IoC 支持者”认为“IoC 就绪”服务应该将 log/trace/authenticate/handleException 事件作为服务合同的一部分发布(然后是的——没有“对基础设施的依赖”)?但这也意味着这样的服务应该是双工的(发布日志事件)......

可能他们的“服务”只是代理?代理不依赖于基础设施,因为所有基础设施都是远程的,但我不高兴发现 IoC 容器应该只用于存储代理。我的失望是对的吗?但是,设计用于在 Unity 容器中处理记录器和处理程序的 MS 企业库呢?

追加:

我是这样理解的:有服务(有合同),有实体(业务),还有基础设施的东西 LogWriter、AuthenticationProvider;- 创建/托管服务我用一些基础设施的东西来启动它(所以我要发布依赖于基础设施而不是实体)。我仍然不明白我是否正确?

附加 2:

经过讨论,我这样理解情况。 ILog 等 - 是服务(即使它们是基础设施服务),因此如果“MyClass”是某些服务的实现,则不违反规则。这意味着规则是好的,但样本是坏的。

还有一个问题:一句话不解释,我还是不明白实体和服务的对立。它们来自不同的概念层:1)服务消息;和2)业务规则实体..所以可能首先我应该采用新的术语。

【问题讨论】:

  • 感谢您的链接。情况对我来说要清楚得多:现在我确定 IoC 当然是关于基础设施建设,而不是关于商业实体建设。并且还想补充一点,在“仅存储服务;不存储任何实体”的规则中,服务和实体之间存在对立,这在教学上是错误的。
  • 如果您采用领域驱动设计中提出的术语,服务和实体是完全不同的两个东西。我认为这没有错。当然,两者仍然是对象... :)
  • 好的。我明白了,我的问题是我感觉不到上下文。对我来说,“服务”是 SOA 的概念。我们有来自 DDD 的“业务服务”。
  • 不幸的是,“服务”这个词实在是太可怕了,以至于几乎毫无意义......

标签: c# inversion-of-control unity-container


【解决方案1】:

简答:实体不应该依赖于服务!这是依赖倒置的“倒置”部分的很大一部分。如您链接到的帖子中所述:

我发现问题示例的设计是错误的,因为实体(MyClass 是)不应该依赖于基础设施(或任何其他)服务。

MyClass,在您的示例中,取决于三个横切关注点,加上IApplicationSettings。如果您愿意,应该使用 AOP/动态代理技术或 pubsub 样式的事件来引入横切关注点。并且MyClass 应该由负责创建其实例的任何服务注入特定于其功能的设置。例如,PersonFactory 可以注入IApplicationSettings,然后创建Person 对象,将appSettings.SomePersonRelatedSetting 传递给Person 构造函数。

【讨论】:

  • 我的理解是有服务(有合同),有实体(业务),还有基础设施的东西 LogWriter,AuthenticationProvider - 创建/托管服务我用一些基础设施的东西来启动它(发布对基础设施的依赖)。我仍然不明白我是否正确。
  • 应用服务依赖基础设施服务没有错;我在链接的文章中没有看到任何反对这一点的内容。使用 AOP/动态代理/pubsub 技术可能仍然更清洁并减少构造函数参数的数量,其中前两个无论如何都是 IoC 容器特性。但这并不像避免实体对服务的依赖那么重要。
【解决方案2】:

规则“仅在 IoC 容器中存储服务。不要存储任何实体。”意味着您应该在 IoC 容器对 interace - implementation 中注册。此规则是dependency inversion principle 的结果。根据您的示例,这意味着您应该从 MyClass 中提取公共接口并使用它而不是 MyClass 实现。

【讨论】:

  • 我认为你没有抓住重点; MyClass 是一个实体,因此不需要为 DIP 目的提取接口。 (它可能仍然有用,例如用于模拟,但这是一个单独的问题。)
  • @Domenic 比基础架构逻辑应该从MyClass 移动到MyClassService,实际上应该实现IMyClassService 接口
【解决方案3】:

说的规则

"Store in IoC container only services. Do not store any entities."

是从概念的角度而不是从实现的角度说话。从概念上讲,实体代表数据(或状态),也许还有与数据相关的规则(作为方法)。服务表示通过已发布的合同公开的功能,通常,状态完整的服务不是一个好主意。因此,尽管 C# class 构造将用于表示服务实现和实体实现——这条规则的意思是只有服务应该被放入 IoC。 IoC 确实充当了一个可配置的超级灵活工厂,为所需的服务合同提供正确的服务实现。同样,可以使用诸如ActiveRecord 之类的模式,其中可能合并了数据和持久性功能——我不喜欢这种模式,但有很多追随者,典型的用法会将这些实体放入 IoC 容器中。但是,重要的区别可能是实体将根据某些合同(而不是实施)进行注册

再次注意,您的代码依赖于服务合同,而不是特定的服务实现。现在,可以通过多种方式公开和解决依赖关系。您可以通过将它们作为构造函数参数或公共属性 getter/setter 或使用声明性语法(如属性)来标记依赖项。这些通常由 DI 框架自动解决。但是,您始终可以通过显式调用(例如ILog log = DIContainer.Get<ILog>();)来获取/解决某些服务。就基础设施服务而言,我认为博客作者所说的是不要将基础设施服务标记为显式依赖项(通过构造函数参数或属性等)。您可以使用代码(如上所述)或使用简单的单例助手等来解决它们。在某种程度上,他是对的,因为人们总是可以假设每个服务/类都依赖于基础设施,因此不需要使用公共 API 声明依赖关系。

【讨论】:

  • 活动记录模式的好例子。它非常不符合 IoC,因为您最终会得到一个依赖于服务(例如 IPersistenceService)的实体(例如 Person)。如果您希望完全接受 IoC,您的实体不应依赖于服务活动记录样式。
  • 对不起,我可能还是问错了问题,但是..根据这个规则,服务实现可以发布它对 LogWriter、AuthenticationProvider 等基础设施的依赖吗?这些东西与实体无关,至少在服务概念层是这样。可能我同意,发布对基础设施的依赖与依赖注入原则有一点共同点。但我发布它们是因为存在这样的依赖关系并且应该解决它们.. 为什么不 IoC 容器?
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2013-08-08
  • 1970-01-01
  • 2012-06-04
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多