7

如果一个对象具有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)
    {
    }
}
4

6 回答 6

10

以下可以接受吗?

类人 {
Person(IStorageService) { } ...
void Save() { } ...
}

这种依赖没有意义。

虽然它没有将 a 强耦合PersonStorage,因为它没有将它们绑定到特定的存储实现,但我认为任何这样的依赖都是没有意义的。

方法作为动词

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

当我作为一个人时,这意味着什么Save

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

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

试图把它塞进去

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

但是你是说一个人有责任知道如何将自己保存到存储中。在我看来,这违反了 SRP。它还显示了域分析的缺失部分

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

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

你应该如何分离你的逻辑

你在这里有三个逻辑:

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

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

ORM 采用的方法是将所有三个概念分开。“Object Relational Mapping”中的“Mapping”就是“Storage of Person”封装的地方。

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

于 2011-11-11T22:33:31.330 回答
4

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

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

于 2011-11-11T21:22:47.307 回答
4

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

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

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

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

于 2011-11-12T08:33:28.757 回答
0

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

于 2011-11-11T21:27:48.523 回答
0

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

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

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

只是我的两分钱。

于 2011-11-11T22:11:01.420 回答
0

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

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

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

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

于 2017-08-27T22:45:17.120 回答