【问题标题】:Domain Driven Design - Inheritance guidance领域驱动设计 - 继承指南
【发布时间】:2021-11-07 15:45:35
【问题描述】:

我开始学习领域驱动设计,在继承方面需要一些指导。

我有以下代表员工的类:

public class Employee
{
    public Guid EmployeeID { get; }

    public String Firstname { get; }

    public String Lastname { get; }

    // Constructor
    private Employee(Guid employeeID, String firstname, String lastname)
    {
        EmployeeID = employeeID;
        Firstname = firstname;
        Lastname = lastname;
    }

    // Factory
    public static Create(Guid employeeID, String firstname, String lastname)
    {
        return new Employee(employeeID, firstname, lastname)
    }

}

问题

员工也可以是公司的所有者,我的问题是如何构建CompanyOwner类?推荐的实现方式是什么?

选项 1:继承 Employee-class

公司老板是员工,所以感觉一种方法可以是继承员工。

但是,这意味着 EmployeeID、Firstname 和 Lastname 属性必须更改为在 Employee-class 中具有受保护的 setter。在 DDD 中可以吗?

public class CompanyOwner : Employee
{
    // ID for the owner (primary key in database)
    public Guid CompanyOwnerID { get; }

    // Constructor
    private CompanyOwner(Guid companyOwnerID, Guid employeeID, String firstName, String lastName)
    {
        CompanyOwnerID = companyOwnerID;        
        EmployeeID = employeeID;        
        Firstname = firstname;
        Lastname = lastname;
    }

    // Factory        
    public static CompanyOwner Create(Guid companyOwnerID, Guid employeeID, String firstname, String lastname)
    {
        return new CompanyOwner(companyOwnerID, employeeID, firstname, lastname);
    }

}

选项 2:员工信息的单独属性

通过这样做,可以调用 Employee-factory 方法。但是我必须通过 MyOwner.EmployeeInfo.Firstname 访问它,只使用 MyOwner.Firstname 会更干净

    public class CompanyOwner
    {
        // Unique ID for the owner (primary key)
        public Guid CompanyOwnerID { get; }

        // Employee info
        public Employee EmployeeInfo { get; }
       
        // Constructor
        private CompanyOwner(Guid companyOwnerID, Guid employeeID, String firstName, String lastName)
        {
            CompanyOwnerID = companyOwnerID;

            // Calling factory-method of Employee-class to set employee-info
            EmployeeInfo = Employee.Create(employeeID, firstName, lastName);
        }

        // Factory        
        public static CompanyOwner Create(Guid companyOwnerID, Guid employeeID, String firstname, String lastname)
        {
            return new CompanyOwner(companyOwnerID, employeeID, firstname, lastname);
        }

    }

选项 3:跳过 CompanyOwner-class 并在 Employee-class 中使用 IsOwner-property

在我的情况下,这实际上不是一个选项,因为员工可以是多家公司的所有者,而且 CompanyOwnerID(所有者的主键)不适合 Employee 类 p>

public class Employee
{
    public Guid EmployeeID { get; }

    public String Firstname { get; }

    public String Lastname { get; }

    public Boolean IsOwner { get; }

    // Constructor
    private Employee(Guid employeeID, String firstname, String lastname, Boolean isOwner)
    {
        EmployeeID = employeeID;
        Firstname = firstname;
        Lastname = lastname;
        IsOwner = isOwner;
    }

    // Factory
    public static Create(Guid employeeID, String firstname, String lastname, Boolean isOwner)
    {
        return new Employee(employeeID, firstname, lastname, isOwner)
    }

}

【问题讨论】:

    标签: inheritance domain-driven-design domain-model


    【解决方案1】:

    一般来说:您的设计已损坏。您没有代表一个人的员工类 - 员工、所有者、实体(实际上是股东的个人、法人实体)具有的任何角色。它们可能是暂时的,它们可能会随着时间而改变(员工来、离职、回来)。 IsOwner 不一定是一个很好的表示,因为 if 指的是可以随时间变化的开/关关系,并且忽略百分比。

    因此,您有一个实体(OOP 术语)“实体”,其子类为 NaturalEntity(人)。实体具有角色 (m:n),角色之一是 - 员工。您可以简化它 - 但如果您这样做(就像您所做的那样),您会遇到各种问题(同样,您所做的),因为您没有对自然实体进行建模。

    是的,在许多情况下,正确地执行它会使事情变得更加复杂 - 但它是稳定的。因此,您的简化对简化案例有好处。那么,您选择哪一个取决于确切的需求——没有上下文就很难回答。上下文是应用程序的确切需求。警告的话,可能会随着时间的推移而改变 - 所以除非它变得非常复杂,否则最好做对,因为当需求发生变化时,替代方案会被卡住。

    【讨论】:

    • 感谢您的回答。如果我理解正确,你建议有两个类,“Person”和“Entity”,其中“Entity”可以有一个或多个角色。然后我们在哪里放置例如“百分比”和其他仅适用于其中一个角色的特定属性的属性?如果您可以在代码中提供一个简短的示例,那将很有帮助
    • 是的。请注意,我确实说 Entity 是 NaturalEntity(这是一个人)或(可能)LEgalEntity(公司)的基类。还处理长期分包商,业主可能是另一家公司
    • 没有简短的例子,抱歉。有一本 gbook - 数据模型资源书,第 1 卷 - 超过 150 页详细介绍了这一点。好的,只有一小部分是关于这部分的——但是这些关系,如果建模得当,是复杂的,人们不做例子,他们写关于它的书。我强烈建议您获取一份副本 - 它不是来自编程,而是从数据/SQL 的角度来看,而是以非常有趣的细节处理所有这些。
    • ClassB继承ClassA的更一般的例子,ClassA时ClassB设置ClassA属性的推荐方式是什么,根据“领域驱动设计”的原则,应该只有private/no设置它的属性?还是在涉及领域驱动设计时应该完全避免继承?
    猜你喜欢
    • 1970-01-01
    • 2021-11-12
    • 2011-10-06
    • 2016-09-29
    • 1970-01-01
    • 1970-01-01
    • 2011-01-30
    • 2011-02-04
    相关资源
    最近更新 更多