注意:以下示例是 C#,但此问题不应特定于任何语言。
因此,我正在使用S# Architecture的变体构建对象域。对于那些不熟悉它的人,为了节省一些阅读时间,这个想法很简单,就是为每个负责加载到/从持久层加载的域对象都有一个数据访问对象接口。可能需要加载/保存给定对象的所有内容都接受该对象的数据访问接口作为依赖项。因此,例如,我们可以有以下内容,其中产品将根据需要延迟加载购买它的客户:
public class Product {
private ICustomerDao _customerDao;
private Customer _customer;
public Product(ICustomerDao customerDao) {_customerDao = customerDao;}
public int ProductId {get; set;}
public int CustomerId {get; set;}
public Customer Customer {
get{
if(_customer == null) _customer = _customerDao.GetById(CustomerId);
return _customer;
}
}
public interface ICustomerDao {
public Customer GetById(int id);
}
这一切都很好,直到您遇到两个对象需要能够相互加载的情况。例如多对一关系,如上所述,产品需要能够延迟加载其客户,但客户也需要能够获得他的产品列表。
public class Customer {
private IProductDao _productDao;
private Product[] _products;
public Customer(IProductDao productDao) {_productDao = productDao;}
public int CustomerId {get; set;}
public Product[] Products {
get{
if(_products == null) _products = _productDao. GetAllForCustomer(this);
return _products;
}
}
public interface IProductDao {
public Product[] GetAllForCustomer(Customer customer);
}
我知道这是一个非常普遍的情况,但我在这方面相对较新。我的绊脚石是实现数据访问对象时要做什么。因为 Customer 依赖于 IProductDao,所以 CustomerDao 实现也必须,反之亦然,ProductDao 必须依赖于 ICustomerDao。
public class CustomerDao : ICustomerDao {
private IProductDao _productDao;
public CustomerDao(IProductDao productDao) {_productDao = productDao;}
public Customer GetById(int id) {
Customer c = new Customer(_customerDao);
// Query the database and fill out CustomerId
return c;
}
}
public class ProductDao : IProductDao {
private ICustomerDao _customerDao;
public ProductDao (ICustomerDao customerDao) {_customerDao = customerDao;}
public Product[] GetAllForCustomer(Customer customer) {
// you get the idea
}
}
在这里我们遇到了问题。没有 IProductDao 就不能实例化 CustomerDao,反之亦然。我的控制容器(温莎城堡)的反转遇到了循环依赖和阻塞。
我提出了一个临时解决方案,其中涉及延迟加载 DAO 对象本身(我将发布此作为答案),但我不喜欢它。这个问题有哪些久经考验的解决方案?
编辑:以上是我实际使用的架构的简化,我不建议有人实际将 DAO 传递给对象。更接近我实际所做的更好的实现类似于 NHibernate 的工作方式,其中实际对象非常简单,上面实际上是继承和覆盖适当字段的代理对象。