gpt4 book ai didi

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

转载 作者:行者123 更新时间:2023-11-30 23:04:37 25 4
gpt4 key购买 nike

我正在用 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 的引用。由于这两个类都是不可变的,因此每个类都必须使用对另一个的引用进行初始化。但这当然是不可能的,因为我无法创建一个引用另一个不存在的对象的对象。

我想到的解决方案:

一个。我想过在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>将代码的执行延迟到稍后,允许两个构造函数完成。

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

  • 让它们可变,或者
  • 从 EmployeeBonus 中取出 Employee

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

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com