【问题标题】:Using DI with a shared library across applications将 DI 与跨应用程序的共享库一起使用
【发布时间】:2011-08-22 23:01:14
【问题描述】:

我面临着一个设计挑战,我似乎无法以令人满意的方式解决。我有一个类库程序集,其中包含我所有的共享 ORM 对象(使用 EntitySpaces 框架)。这些对象在 2 个或更多不同的应用程序中使用,这就是它们在自己的程序集中的原因。这个设置对我来说已经运行了 4 年多。

我还有几个基于 Microsoft 模式与实践组 (P&P) 的复合应用程序块 (CAB) 构建的应用程序。是的,我知道这真的很老了,但我是一名兼职开发人员,一个人的商店,无法更新到当前的框架。

这就是我的问题所在:我一直在锻炼我的 OO 设计技能,每当进行大量重构时,我都会尝试从程序方法转变为更 OO 的方法。当然,OO 设计的一个主要方面是将操作放置在它们使用的数据附近,这意味着我的 ORM 对象需要在适当的地方添加功能。当我还考虑到我在 CAB 中使用 P&P 的 Object Builder DI 容器并且我将移动到我的 ORM 对象中的大部分功能都需要访问我的应用程序公开的服务时,这证明是一个真正的难题。

换句话说,假设我有一个名为“Person”(我知道是原始的)的共享业务对象,并且我有两个应用程序与一个人做完全不同的事情。应用程序 A 提供了一组服务,Person 对象需要对这些服务进行 DI,以便它采用当前在我的服务层中散布的一些方法。应用程序 B 还具有一组不同的服务,IT 需要将其 DI 到人员对象中。

考虑到 P&P 对象构建器如何使用属性修饰和类型反射来解决依赖关系,我不知道如何实现这一点。简而言之,我有一个共享对象,当在各种应用程序中使用它时,我需要注入依赖项,以便它可以执行特定于该应用程序的某些操作。

我能想到的唯一方法是从 Person 对象继承 Application A & B 中的新类型。然后,我会将我的非共享功能和 DI 代码添加到这个特定于应用程序的专用 Person 对象中。既然我写了它似乎很明显,但这仍然是我能想出的唯一解决方案,我想在这里问一下是否有其他人想提出不同的解决方案?

我的解决方案会遇到的一个问题是,我可以看到自己正忙于命名我的继承类型 - 我的意思是......它是一个人,那么你还会怎么称呼它?无论如何,希望你能给我一些想法。

另外,我对现有的技术并不感兴趣,说实话,我只是勉强掌握我目前使用的技术。因此,如果我说了一些自相矛盾或令人困惑的话,我希望您能从帖子的其余部分中充分理解,以了解我的要求。

【问题讨论】:

  • 为了确保我理解,由自定义属性引起的耦合是主要问题?
  • 虽然您可以将实现放在接近 OO 中的数据的位置,但我不确定这是否是良好 OO 设计的要求。事实上,有时这是个坏主意。
  • @Brook 我认为问题实际上是我正在尝试做的事情是不可能的(或明智的)!我试图找到一种方法来向共享对象(“人”)添加功能,而不会将对象耦合到特定于应用程序的(非共享)接口。当然,我需要将 Person 对象耦合到它需要的接口。
  • 虽然这可能被认为是滥用 SRP,但有时为公共对象制作特定于应用程序的扩展方法非常方便。

标签: c# oop orm dependency-injection


【解决方案1】:

我可以想出几种方法来解决这个问题。

  • 分别分离出特定于每个人/应用程序的行为。在应用程序本身中使用 setter 执行依赖注入。

方法1


public interface IPerson 
{
 IPersonApp1 Person1 {get; set;}
 IPersonApp2 person2 {get; set;}
}

class Person : IPerson
{
 IPerson1 Person1 {get; set;}
 IPerson2 Person2 {get; set;}
}

   public interface IPerson1
  {
    // App1 specific behavior here
     void App1SpecificMethod1();
  }
  class Person1: IPerson1
   {
     void App1SpecificMethod1()
      {
       // implementation
      }
   }

class App1 
{
   IPerson objPerson;
   // Dependency injection using framework
   App1(IPerson objPerson)
  {
    this.objPerson = objPerson;
    // Dependency injection using setter
    this.objPerson.Person1 = new Person1();
  }
}

  • 分别分离出特定于每个人/应用程序的行为。在 Person 构造函数中执行依赖注入。

方法2


class Person : IPerson
{
 IPerson1 Person1 {get; private set;}
 IPerson2 Person2 {get; private set;}
 // DI through constructor. If the type IPerson1 or IPerson2 are not registered, it will be set to null.
 Person(IPerson1 objPerson1, IPerson2 objPerson2)
 {
   this.Person1 = objPerson1;
   this.Person2 = objPerson2;
 }
}

Person 接口项目需要引用 IPerson1 和 IPerson2 或者您可以在 Person 接口项目本身中声明 IPerson1 和 IPerson2。

【讨论】:

    【解决方案2】:

    听起来你正在破坏Single Responsibility Principle

    Person 对象应该只是保存个人记录的数据。然后,服务将接收 Person 对象并对其进行操作,而不是在 Person 对象上使用方法来进行操作。

    一个典型的例子是填充Person 对象。假设应用 A 从 WebService 中获取数据,而应用 B 从数据库中获取数据。在这些情况下,我会调用某种Storage 服务来获取Person 对象。然后,该存储的实现可以特定于每个应用程序,并由应用程序放入您的 IOC,而不是尝试在您的共享程序集中拥有一个通用接口。

    【讨论】:

    • 在我阅读 SRP 之前,我认为我对您的帖子有很好的回应;) 我必须承认我现在有点困惑,我非常有信心向对象添加行为是“好的面向对象设计”。例如,如果我想加载一个客户订单,我可以调用 aCustomer.GetOrders() 而不是 aOrderService.GetCustomerOrders(aCustomer) 后者是我目前正在做的;我有一大堆服务对象,我将它们注入我的 Presenter 对象以及注入其他服务。
    【解决方案3】:

    我同意 Cameron MacFarland 的观点:您正在破坏 SRP。

    当然是面向对象设计的一个主要方面 正在将操作靠近 他们使用的数据,这意味着 我的 ORM 对象需要有 添加到其中的功能 合适的

    从 A 中放置数据和功能并从 B 中放置功能是两个过多的责任。遵守 SRP 几乎总是会导致在单独的类(数据结构和对象)中分离数据和功能。因此,使用 Cameron MacFarlands 的建议可能是最好的方法。

    【讨论】:

    • 我也同意我正在破坏 SRP。正如我在对卡梅伦的评论中提到的那样,我对此感到非常惊讶,并为自己如此严重地错过了分数而感到有点愚蠢。我有一些阅读要做,我必须弄清楚为什么我认为应该将行为添加到对象而不是使用服务对象
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2013-11-02
    • 1970-01-01
    • 1970-01-01
    • 2016-02-22
    • 2023-03-21
    • 2011-03-05
    • 1970-01-01
    相关资源
    最近更新 更多