领域驱动设计(DDD)继承实践咨询:CompanyOwner类的推荐实现方案
DDD实体继承场景实现方案解答
问题背景
提问者刚接触领域驱动设计,当前有基础的Employee员工实体类,需要实现公司所有者CompanyOwner的相关逻辑,现有三类实现方案,需要评估最优解。
原有Employee类代码:
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 Employee Create(Guid employeeID, String firstname, String lastname) { return new Employee(employeeID, firstname, lastname); } }
注:原代码工厂方法遗漏返回值类型,已补全
现有方案评估
方案1:继承Employee类
逻辑思路:公司所有者属于员工,直接继承Employee类实现,需要修改父类属性为protected set权限。
该方案的核心问题是违背DDD优先组合而非继承的设计原则,继承是强耦合的is-a关系,无法支持一个员工同时担任多家公司所有者的业务场景,且修改父类访问权限会破坏原有实体的封装性,后续扩展其他员工角色时会出现类爆炸问题,不推荐使用。
对应代码:
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属性
逻辑思路:CompanyOwner类中内置Employee类型的属性保存员工信息,直接调用原有Employee的工厂方法初始化。
该方案是DDD处理角色类场景的标准实践,耦合度低、扩展性强,唯一的属性访问不够简洁的问题可以通过增加透传属性轻松解决,是最优选择。
对应代码:
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:Employee类新增IsOwner标记
逻辑思路:移除CompanyOwner类,直接在Employee实体中加IsOwner字段标记是否为公司所有者。
该方案提问者已明确不可行,确实不符合员工可担任多家公司所有者的业务规则,且CompanyOwnerID主键无法放到Employee类中,排除该方案。
对应代码:
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 Employee Create(Guid employeeID, String firstname, String lastname, Boolean isOwner) { return new Employee(employeeID, firstname, lastname, isOwner); } }
优化后的推荐实现
针对方案2的属性访问问题,新增透传属性优化,最终实现代码如下:
public class CompanyOwner { public Guid CompanyOwnerID { get; } public Employee EmployeeInfo { get; } // 透传员工属性,简化调用 public Guid EmployeeID => EmployeeInfo.EmployeeID; public string Firstname => EmployeeInfo.Firstname; public string Lastname => EmployeeInfo.Lastname; private CompanyOwner(Guid companyOwnerID, Employee employee) { // 可补充参数合法性校验 if (companyOwnerID == Guid.Empty) throw new ArgumentException("所有者ID不能为空", nameof(companyOwnerID)); EmployeeInfo = employee ?? throw new ArgumentNullException(nameof(employee)); CompanyOwnerID = companyOwnerID; } public static CompanyOwner Create(Guid companyOwnerID, Guid employeeID, string firstname, string lastname) { var employee = Employee.Create(employeeID, firstname, lastname); return new CompanyOwner(companyOwnerID, employee); } // 重载工厂方法,支持传入已有的Employee实例 public static CompanyOwner Create(Guid companyOwnerID, Employee employee) { return new CompanyOwner(companyOwnerID, employee); } }
该实现的优势:
- 完全保留原有
Employee类的封装性,符合开闭原则,不需要修改任何原有代码 - 天然支持一个员工对应多个
CompanyOwner实例,匹配多公司所有者的业务需求 - 透传属性保证了调用的简洁性,不需要嵌套访问员工信息
- 后续扩展所有者专属逻辑(如股权比例、关联公司ID、所有者权限等)不会影响员工类的逻辑
内容的提问来源于stack exchange,提问作者Marcus
相关产品推荐
相关产品推荐

