Now that our CustomerRepository can save customers as well as associated addresses in a decoupled manner we need to move onto the next problem, reconstituting our customer object with an address. As others have mentioned we may want to Lazy Load the address since there will be instances when it isn't needed.
public class Customer {
public int addressKey;
public Address Address {
get {
if(address == null) {
address = new AddressRepository().Load(addressKey);
}
return address;
}
}
Ok, so the above would work but is it really what we want? Using the above method we introduce a coupling between our Customer class and the AddressRepository. I'd like to remove the coupling to allow us to support different address repositories as we can with the .Save within our CustomerRepository (via RepositoryFactory). I'd also like to remove any knowledge of repositories from my domain objects. Although it isn't always possible I prefer for application code to have knowledge of repositories NOT my domain objects. So how can we remove the coupling to the AddressRepository AND remove the Repository outright?
public class Customer {
public int addressKey;
public Address address;
public Address Address {
get { return address; }
}
}
One option is to have to separate methods on our CustomerRepository for returning Customer objects with and without Addresses loaded.
public class CustomerRepository : DomainRepository {
public Customer Load(int customerKey) {
Customer customer = RetrieveFromDataStore(customerKey);
return customer;
}
public Customer LoadWithAddress(int customerKey) {
Customer customer = Load(customerKey);
DomainRepository addressRepository = this.RepositoryFactory.GetRepository(typeof(Address));
customer.Address = addressRepository.Load(customer.AddressKey);
return customer;
}
}
The negative to the above is that we have two different methods for loading customers. If we use .Load() and then try and access the address property we get a null which could cause users of the class to think that the Customer doesn't have an address which is not the case. On the positive side using the above design forces the users of the class to think about how the customer is going to be used. Rather then lazy loading the address we have it pre-populated which ensures we don't run into performance problems due to users not realizing that the property is lazy loaded and causing additional hits to the database. What other options do we have? Perhaps introducing a proxy object could help?
public class Customer {
public Address Address {
get { return addressProxy.Address; }
}
protected internal AddressProxy AddressProxy {
set { addressProxy = value; }
}
}
public class AddressProxy {
private int addressKey;
private DomainRepository addressRepository;
private Address Address;
public AddressProxy(int addresskey, DomainRepository addressRepository) {
this.addressKey = addressKey;
this.addressRepository = addressRepository;
}
public Address Address {
get {
if(address == null) {
address = addressRepository.Load(addressKey);
}
return address;
}
}
And our CustomerRepository Load methods change to:
public class CustomerRepository {
public Customer Load(int customerKey) {
Customer customer = Load(customerKey);
DomainRepository addressRepository = this.RepositoryFactory.GetRepository(typeof(Address));
customer.AddressProxy = new AddressProxy(customer.AddressKey, addressRepository);
return customer;
}
}
The negative's of this solution is that we're introducing the proxy class into the Customer which is a little messier then I'd like. It'd be nice if our AddressProxy could inherit from our Address and provide a nice way of handling the loading of itself so that the Customer didn't have to use the AddressProxy. We could have the proxy overload all the properties of the address but that would be pretty ugly for all but the simplest of classes. I'm still not real pleased with the solution that I came up with here but it's at least a start. Perhaps all of my wonderful readers can help improve the "design"?