C# 设计问题 : two immutable objects with references to each other

标签 c# oop

我正在用 C#/WPF 编写一个相当大的应用程序。我使用Builder模式来创建始终处于一致状态的对象,并且对象是不可变的。

我在这个设计中遇到了一个问题,我不知道如何解决。

考虑以下两个类:

public class Employee {
    public string Name { get; }
    public double Salary { get; }
    public IReadOnlyList<EmployeeBonus> Bonuses { get; } // read-only list of bonuses

    public Employee(string name, double salary, IEnumerable<EmployeeBonus> bonuses) {
        Name = name;
        Salary = salary;
        Bonuses = new List<EmployeeBonus>(bonuses); // list of bonuses initialized in constructor
    }
}

public class EmployeeBonus {
    public Employee Employee { get; } // bonus has reference to Employee
    public string Description { get; }
    public double Amount { get; }

    public EmployeeBonus(Employee employee, string description, double amount) {
        Employee = employee; // employee must be initialized in constructor
        Description = description;
        Amount = amount;
    }
}

所以 - 我有一个 Employee 类,其中包含每个员工收到的奖金列表。 EmployeeBonus 类包含对 Employee 的引用。 由于这两个类都是不可变的,因此必须通过对另一个类的引用来初始化每个类。但这当然是不可能的,因为我无法创建一个引用另一个不存在的对象的对象。

我想到的解决方案:

A.我想过在EmployeeBonus中不要引用Employee,所以EmployeeBonus只需要构建Description和Amount。但这打破了我的存储库模式:我的 Repository<EmployeeBonus>有一个仅接受 EmployeeBonus 的 Add 方法。为了正确保存该对象,我需要知道哪个员工拥有它,并且因为该方法仅接受 EmployeeBonus - 该对象必须包含 Employee。

B.我考虑过向 Employee 添加一个 AddBonus(string description, double amount) 方法,以便奖金列表不在构造函数中初始化,而是稍后添加每个奖金,并且 Employee 类将自身附加到每个奖金 - 但这会使 Employee 不再是一成不变的。

C.我可以破坏我的通用存储库并创建另一个方法,Add(EmployeBonus bonus, Employee employee) ,然后从 EmployeeBonus 中删除 Employee - 但这样我的 EmployeeBonusRepository 将不会继承 Repository<EmployeeBonus> .

D.我能想到的最正确的解决方案(正确但非常浪费)是这样的:

public class Employee 
{
    public string Name { get; }
    public double Salary { get; }
    public IReadOnlyList<EmployeeBonus> Bonuses { get; }

    public Employee(string name, double salary, IEnumerable<EmployeeBonus> bonuses) {
        Name = name;
        Salary = salary;
        Bonuses = new List<EmployeeBonus>(bonuses);
    }
}

public class EmployeeBonus 
{
    public string Description { get; }
    public double Amount { get; }

    public EmployeeBonus(string description, double amount) {
        Description = description;
        Amount = amount;
    }
}

public class EmployeeBonusWithEmployee 
{
    public Employee Employee { get; }
    public EmployeeBonus Bonus { get; }

    public EmployeeBonusWithEmployee(Employee employee, EmployeeBonus bonus) 
    {
        Employee = employee;
        Bonus = bonus;
    }
}

public class EmployeeBonusWithEmployeeRepository : Repository<EmployeeBonusWithEmployee>
{
    public void Add(EmployeeBonusWithEmployee bonus)
    {
        // save complete employee bonus
    }
}

public class EmployeeRepository : Repository<Employee>
{
    //...
    public void Add(Employee employee)
    {
        // saves employee first, 
        // then creates an EmployeeBonusWithEmployee object for each EmployeeBonus in the list
        // and saves it using an EmployeeBonusWithEmployeeRepository
    }
}

这个解决方案 (D) 有意义吗?有更优雅的方法吗?

最佳答案

要在 C# 中创建相互引用的对象,您需要延迟执行相互引用的代码 - 直到两个对象都已创建。

 public class B
 {
     private Lazy<A> _a;

     public A GetA 
     { 
         get { return _a.Value; } 
     }

     public B(Lazy<A> forLater)
     {
         _a = forLater;
     }
 }

与 A 类相同。 然后创建相互引用的对象:

 A a = null;
 B b = null;

 a = new A(new Lazy<B>(() => b));
 b = new B(new Lazy<A>(() => a));

Lazy<T>将代码的执行延迟到稍后,从而允许两个构造函数完成。

这是一个糟糕的解决方案 - 其他语言使这变得更容易 - 所以我建议一个更实用的方法。

  • 使它们可变,或者
  • 将员工从员工奖金中剔除

关于C# 设计问题 : two immutable objects with references to each other,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/49304616/

相关文章:

c - 如何在C中创建函数对象

c# - 使两个并行继承结构跨层交互的方法

.net 收藏 : how to copy objects from one collection to another?

c# - 错误地收到消息 "Edits were made to the code which cannot be applied while debugging"

c# - Action 过滤器 + AspNetRedisProvider

c# - 有没有办法让比较更短

c# - 如何使用 Moq 为异步函数抛出异常

c# - 方法的返回值正在修改作为方法参数传递的对象

使用 String 的 DefineProperty 的 Javascript getter 返回 null

c# - 如何播放 WPF 声音文件资源