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

如何设计CarInfo类的客户成员,支持Customer对象或独立姓名?

问题描述

我有一个用于存储车辆及其车主信息的CarInfo类。车主分为两种情况:一是已知客户(可查询并填充Customer类实例),二是仅知晓姓名(无法填充Customer类)。当前的类设计如下:

public class CarInfo
{
     public Guid Id { get; }
     // 其他属性...
     public Customer? Customer { get; set; }           // 要么填充该成员
     public string? FirstName { get; set; }   // 要么填充姓和名字段
     public string? LastName { get; set; }
     // 其他属性...
}

请问处理这种情况的最佳设计方案是什么?是否应将客户相关信息拆分到新的CustomerInfo类中,通过多态来处理,例如:

public class CustomerInfo
{
   public Customer? Customer { get; private set; }
   public string? FirstName { get; private set; }
   public string? LastName { get; private set; }

   public CustomerInfo(Customer customer) => Customer = customer;
   public CustomerInfo(string firstName, string lastName)
   {
      FirstName = firstName;
      LastName = lastName;
   }
}

并在CarInfo中这样使用?

public class CarInfo
{
    public Guid Id { get; }
    // 其他属性...
    public CustomerInfo OwnerInfo { get; set; }           
    // 其他属性...
}

我不确定应参考哪些最佳实践或设计模式。


解决方案

你的思路方向是对的——原设计的核心问题是无法保证车主信息的状态一致性:如果同时给Customer和FirstName/LastName赋值,会导致数据矛盾,后续业务逻辑处理时容易出错。下面给出两种符合最佳实践的优化方案,可根据场景选择:

方案一:封装互斥状态的CustomerInfo类(简单实用)

直接基于你的思路优化,通过封装确保两种车主状态互斥,同时提供统一的访问接口,避免外部处理时的判断逻辑:

public class CustomerInfo
{
    public Customer? KnownCustomer { get; }
    public string? FirstName { get; }
    public string? LastName { get; }

    // 已知客户的构造函数,确保参数非空
    public CustomerInfo(Customer customer)
    {
        KnownCustomer = customer ?? throw new ArgumentNullException(nameof(customer));
        // 从Customer同步姓名,确保外部获取的姓名一致
        FirstName = customer.FirstName;
        LastName = customer.LastName;
    }

    // 仅知姓名的构造函数,确保至少有一个姓名字段有效
    public CustomerInfo(string firstName, string lastName)
    {
        if (string.IsNullOrWhiteSpace(firstName) && string.IsNullOrWhiteSpace(lastName))
            throw new ArgumentException("至少需要提供姓名的一部分");
        FirstName = firstName;
        LastName = lastName;
    }

    // 统一获取全名的方法,外部无需判断类型
    public string GetFullName()
    {
        return KnownCustomer != null 
            ? $"{KnownCustomer.FirstName} {KnownCustomer.LastName}".Trim() 
            : $"{FirstName} {LastName}".Trim();
    }
}

然后修改CarInfo:

public class CarInfo
{
    public Guid Id { get; }
    // 其他车辆属性...
    public CustomerInfo OwnerInfo { get; set; }
    // 其他属性...
}

优势

  • 彻底避免状态不一致:构造函数只能选择一种车主类型,不会出现同时赋值的情况
  • 封装了车主信息的逻辑,CarInfo只需关注车辆本身,符合单一职责原则
  • 对外提供统一的访问方式(如GetFullName),减少外部代码的判断逻辑

方案二:多态抽象设计(灵活扩展)

如果未来可能新增更多车主类型(比如公司车主、临时车主),可以用抽象基类+派生类的多态设计,符合开闭原则(新增类型无需修改现有代码):

// 抽象基类,定义车主信息的统一接口
public abstract class OwnerInfo
{
    public abstract string GetFullName();
}

// 已知客户的派生类
public class KnownCustomerOwner : OwnerInfo
{
    public Customer Customer { get; }

    public KnownCustomerOwner(Customer customer)
    {
        Customer = customer ?? throw new ArgumentNullException(nameof(customer));
    }

    public override string GetFullName()
    {
        return $"{Customer.FirstName} {Customer.LastName}".Trim();
    }
}

// 仅知姓名的派生类
public class AnonymousOwner : OwnerInfo
{
    public string FirstName { get; }
    public string LastName { get; }

    public AnonymousOwner(string firstName, string lastName)
    {
        if (string.IsNullOrWhiteSpace(firstName) && string.IsNullOrWhiteSpace(lastName))
            throw new ArgumentException("至少需要提供姓名的一部分");
        FirstName = firstName;
        LastName = lastName;
    }

    public override string GetFullName()
    {
        return $"{FirstName} {LastName}".Trim();
    }
}

修改CarInfo使用抽象基类:

public class CarInfo
{
    public Guid Id { get; }
    // 其他车辆属性...
    public OwnerInfo OwnerInfo { get; set; }
    // 其他属性...
}

优势

  • 多态特性让外部代码无需判断车主类型,直接调用抽象方法即可
  • 新增车主类型时只需添加新的派生类,无需修改现有业务逻辑
  • 每个派生类只负责一种车主的逻辑,职责更清晰

方案选择建议

  • 如果只是固定两种车主类型,优先选方案一,实现简单,维护成本低
  • 如果未来有扩展需求,或者需要处理更复杂的车主逻辑,选方案二,灵活性更高

内容的提问来源于stack exchange,提问作者Peter Rundqvist

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.16 23:27:43