You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用设计模式实现自然人/法人Person类的最优方案咨询

最佳实现方案

推荐设计模式:多态继承 + 工厂方法模式

现有Person类的原生写法只能靠业务代码人工保证自然人、法人关联关系互斥,没有强制校验机制,很容易出现非法的脏数据。采用多态继承配合工厂方法是最贴合需求的实现方案:

  1. 将Person调整为抽象基类,提取自然人、法人共有的属性到基类中,PersonReal(自然人)和PersonLegal(法人)作为子类继承Person,天然保证一个Person实例只能属于其中一种类型,从面向对象特性层面就杜绝了同时属于两种类型的可能。
  2. 配合工厂方法模式封装实例创建逻辑,避免上层业务直接实例化子类,统一控制实例创建规则,降低业务代码出错概率。

代码实现示例

// 抽象Person基类
public abstract class Person
{
    public Guid Id { get; set; }
    public string Title { get; set; }
    // 其他所有自然人、法人共有的属性可统一放到此处
}

// 自然人类
public class PersonReal : Person
{
    public Guid Sex { get; set; }
    public string FirstName { get; set; }
}

// 法人类
public class PersonLegal : Person
{
    public string Name { get; set; }
    public Guid? TopManager { get; set; }
    public string NationalCode { get; set; }
}

// 工厂类,封装实例创建逻辑
public static class PersonFactory
{
    public static Person CreateRealPerson(string title, Guid sex, string firstName)
    {
        return new PersonReal
        {
            Id = Guid.NewGuid(),
            Title = title,
            Sex = sex,
            FirstName = firstName
        };
    }

    public static Person CreateLegalPerson(string title, string name, Guid? topManager, string nationalCode)
    {
        return new PersonLegal
        {
            Id = Guid.NewGuid(),
            Title = title,
            Name = name,
            TopManager = topManager,
            NationalCode = nationalCode
        };
    }
}

如果使用Entity Framework做数据持久化,可以直接用TPH(Table Per Hierarchy)映射策略,所有Person子类数据存在同一张表中,EF会自动生成Discriminator列标记实例类型,不需要额外处理关联关系。


兼容原有结构的备选方案:类型状态模式

如果因为历史代码/表结构约束,无法调整继承关系,可以用类型状态模式,增加身份类型枚举+属性赋值校验,强制保证关联关系互斥:

public enum PersonType
{
    Unknown,
    Real,
    Legal
}

public class Person 
{
    public Guid Id { get; set; }
    private PersonType _type = PersonType.Unknown;
    private Guid? _personRealId;
    private Guid? _personLegalId;
    private PersonReal _personReal;
    private PersonLegal _personLegal;

    public PersonType Type => _type;

    public Guid? PersonRealId 
    { 
        get => _personRealId; 
        set 
        {
            if (value.HasValue && _personLegalId.HasValue)
                throw new InvalidOperationException("同一Person实例不能同时关联自然人和法人");
            _personRealId = value;
            _type = value.HasValue ? PersonType.Real : PersonType.Unknown;
        } 
    }

    public Guid? PersonLegalId 
    { 
        get => _personLegalId; 
        set 
        {
            if (value.HasValue && _personRealId.HasValue)
                throw new InvalidOperationException("同一Person实例不能同时关联自然人和法人");
            _personLegalId = value;
            _type = value.HasValue ? PersonType.Legal : PersonType.Unknown;
        } 
    }

    public virtual PersonReal PersonReal 
    { 
        get => _personReal; 
        set 
        {
            if (value != null && _personLegal != null)
                throw new InvalidOperationException("同一Person实例不能同时关联自然人和法人");
            _personReal = value;
            _personRealId = value?.Id;
            _type = value != null ? PersonType.Real : PersonType.Unknown;
        } 
    }

    public virtual PersonLegal PersonLegal 
    { 
        get => _personLegal; 
        set 
        {
            if (value != null && _personReal != null)
                throw new InvalidOperationException("同一Person实例不能同时关联自然人和法人");
            _personLegal = value;
            _personLegalId = value?.Id;
            _type = value != null ? PersonType.Legal : PersonType.Unknown;
        } 
    }
}

该方案不需要改动现有表结构,所有互斥校验在属性赋值时自动触发,能有效避免非法数据写入。

内容的提问来源于stack exchange,提问作者Javad Azimi

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.28 21:54:04