【问题标题】:Single Responsibility and dependencies单一职责和依赖关系
【发布时间】:2011-12-27 08:27:34
【问题描述】:

如果一个对象有一个Single Responsibility,以下是否可以接受:

public class Person
{
   public string Name;
   public DateTime DateOfBirth;

   private IStorageService _storageService;

   public Person(IStorageService storageService)
   {
      _storageService = storageService
   }

   public void Save()
   {
        _storageService.Persist(this);
   }
}

即使用提供的协作者(这也有助于防止领域模型出现问题)。

或者应该是:

public class Person
{
   public string Name;
   public DateTime DateOfBirth;

   public Person()
   {
   }


}
public class StorageService
{
    public void Persist(Person p)
    {
    }
}

【问题讨论】:

  • 我一般都见过后者。前者有什么优势?
  • 我认为 person 类没有真正了解 storageservice 的业务,它将 person 类与存储服务耦合在一起,这使得它的可重用性降低

标签: c# oop dependency-injection single-responsibility-principle


【解决方案1】:

我会坚持使用第二个版本。如果它具有单一职责,您可以使用第一个版本。但是,在我看来,我喜欢将持久层与模型对象分开。

另外,您可以序列化第二个版本,这会很有帮助。您可能无法使用对 IStorageService 的引用来序列化第一个版本。

【讨论】:

    【解决方案2】:

    我发现您的域命名空间越完整和经过测试,您的应用程序的质量就越好。持久化实体不属于领域模型,所以我将两者分开。

    【讨论】:

      【解决方案3】:

      如果 person 是您正在建模的域对象,我不提倡将其封装为服务。我的意思是,我不了解你,但我是一个人,我没有存储服务;)

      我想说,对贫血域模型的关注是对域对象如何相互关联的关注。如果它们只是文字的属性包,那将是贫血的。您可能不想通过让他们关注建模事物以及弄清楚何时以及如何坚持自己来解决这个问题。

      贫乏的领域考虑将通过丰富的互动得到补救。也许您正在为一所学校建模,Person 是一个可以是 Student 或 Teacher 的对象,Class 是学生和老师的集合。然后你会有某种 myTeacher.Assign(Homework hw, Class class) 或类似的概念。这就是我个人将如何丰富我的域模型 - 通过对域实体之间的实际概念交互进行建模,而不是通过“建模”它们与数据访问管道代码的交互方式。

      只要我的两分钱。

      【讨论】:

        【解决方案4】:

        以下是否可以接受?

        类人{
        人(IStorageService){ } ...
        无效 Save() { } ...
        }

        这种依赖没有意义。

        虽然它不会将Person 强耦合到Storage,因为它不会将它们绑定到特定 存储实现,但我认为任何此类依赖都没有意义。

        方法作为动词

        将类上的方法想象成由该类型执行的动词。您是在告诉该类型的实例相对于其本地域“做某事”。

        作为一个人,Save 是什么意思?

        • 我更换了保险公司并将成本降低了 15%?
        • 我是救赎之神?
        • 我已将我的灵魂下载到一个自动机中?

        存储服务可以而且应该Save。人们不能Save,也不应该宣传他们可以。

        试着把它塞进去

        SaveTo 可能更有意义 - 即public void SaveTo(IStorageService storage)

        但是你是说一个人有责任知道如何将自己保存到存储中。在我看来,这是a violation of SRP。它还显示a missing piece of Domain Analysis

        Person 的域不会包含有关保存、存储等的任何内容。它将包含人之间的交互,以及该域级别的其他事物。数据持久化领域是Save 方法的更好地方。

        如果Person 位于问题域中(在该抽象级别),则Storage 位于解决方案域中。

        你应该如何分离你的逻辑

        这里有三个逻辑:

        1. Person - 了解“人事”
        2. Storage - 了解特定类型的存储以及如何访问它
        3. Storage of Person - 知道一个人应该如何致力于存储

        按照我上面的建议,我会离开 Person 自行站立。但是,您可以将StorageStorage of Person 的逻辑分开,也可以将它们组合起来。

        The approach that ORMs take 是将所有三个概念分开。 “Object Relational Mapping”中的“Mapping”就是封装了“Storage of Person”的地方。

        这种方法允许您的Storage 逻辑专注于读取存储配置、连接到存储、确保存储速度快、选择替代存储方法等潜在的复杂工作。它还消除了对主域模型的任何依赖,因此存储代码可以被任何其他领域模型重用。

        【讨论】:

          【解决方案5】:

          如果您仔细阅读SRP 的定义,您会注意到责任的定义是改变的原因

          第一个版本可能有两个改变的原因:

          • 持久性 API 发生变化
          • 其值的形状发生变化

          因此,它不遵守 SRP,而第二个版本则如此。

          【讨论】:

            【解决方案6】:

            根据单一职责原则,一个类应该只有一个改变的理由。更改的原因或来源是我们为其创建和设计不同类的不同业务部门。

            因此,要知道是否存在违反 SRP 的情况,设计师需要了解他工作的不同业务部门并设计类,以便没有一个类具有多个部门的行为或状态。这可能因企业而异。

            尽管在您给出的第一个示例中,很明显可能有两个变化来源,即客户经理(用于管理客户姓名、出生日期)和数据库管理员/模式设计器(将客户保存到数据库)。所以它显然违反了 SRP。

            在第二个示例中,您在两个不同的类中管理两个不同的变化源。所以,我想说第二个示例是正确的。虽然我会更改班级名称:)。

            【讨论】:

              猜你喜欢
              • 2010-12-18
              • 2011-03-17
              • 1970-01-01
              • 2020-08-13
              • 1970-01-01
              • 1970-01-01
              • 2010-11-26
              • 2016-07-31
              • 2019-06-30
              相关资源
              最近更新 更多