回复@Jason D,并为@Nitax 着想:我真的是在略过表面,因为虽然它基本上很容易,但它也可能变得复杂。我也不会比 Martin Fowler 更好地重写它(当然不会在 10 分钟内)。
您首先必须解决内存中只有 1 个对象引用特定仓库的问题。我们将通过称为存储库的东西来实现这一点。 CustomerRepository 有一个GetCustomer() 方法,DepotRepository 有一个GetDepot() 方法。我要挥挥手,假装这一切都发生了。
其次,您需要编写一些测试来表明您希望代码如何工作。我不知道,但不管怎样,请耐心等待。
// sample code for how we access customers and depots
Customer customer = Repositories.CustomerRepository.GetCustomer("Bob");
Depot depot = Repositories.DepotRepository.GetDepot("Texas SW 17");
现在困难的部分是:你想如何塑造这种关系?在 OO 系统中,您实际上不必做任何事情。在 C# 中,我可以执行以下操作。
客户保留他们所在仓库的列表
class Customer
{
public IList<Depot> Depots { get { return _depotList; } }
}
或者,仓库会保留一份与他们合作的客户的列表
class Depot
{
public IList<Customer> Customers { get { return _customerList; } }
}
// * code is very brief to illustrate.
在最基本的形式中,任意数量的客户可以引用任意数量的仓库。 m:n 解决了。 OO 中的引用很便宜。
请注意,我们遇到的问题是,虽然客户可以保留对其关心的所有仓库的引用列表(第一个示例),但对于仓库来说,枚举所有客户并不容易。
要获取仓库的所有客户列表(第一个示例),我们必须编写代码来迭代所有客户并检查 customer.Depots 属性:
List<Customer> CustomersForDepot(Depot depot)
{
List<Customer> allCustomers = Repositories.CustomerRepository.AllCustomers();
List<Customer> customersForDepot = new List<Customer>();
foreach( Customer customer in allCustomers )
{
if( customer.Depots.Contains(depot) )
{
customersForDepot.Add(customer);
}
}
return customersForDepot;
}
如果我们使用的是 Linq,我们可以这样写
var depotQuery = from o in allCustomers
where o.Depots.Contains(depot)
select o;
return query.ToList();
有 10,000,000 个客户存储在数据库中吗? 哎呀! 您真的不想每次 Depot 需要确定其客户时都加载所有 10,000,000 个客户。另一方面,如果您只有 10 个 Depot,则不时加载所有 Depot 的查询并不是什么大问题。 您应该始终考虑您的数据和数据访问策略。
我们可以在Customer 和Depot 中都有列表。当我们这样做时,我们必须小心执行。添加或删除关联时,我们需要同时更改两个列表。否则,我们的客户会认为他们与仓库相关联,但仓库对客户一无所知。
如果我们不喜欢这样,并决定我们真的不需要将对象耦合得如此紧密。我们可以删除显式列表并引入第三个对象,它只是关系(并且还包括另一个存储库)。
class CustomerDepotAssociation
{
public Customer { get; }
public Depot { get; }
}
class CustomerDepotAssociationRepository
{
IList<Customer> GetCustomersFor(Depot depot) ...
IList<Depot> GetDepotsFor(Customer customer) ...
void Associate(Depot depot, Customer customer) ...
void DeAssociate(Depot depot, Customer customer) ...
}
这是另一种选择。关联的存储库不需要公开它如何将客户与仓库关联(顺便说一下,据我所知,这是@Jason D 的代码试图做的)
在这种情况下,我可能更喜欢单独的对象,因为我们所说的是 Customer 和 Depot 的关联本身就是一个实体。
所以继续阅读一些领域驱动设计书籍,并购买 Martin Fowlers PoEAA(企业应用程序架构模式)