DDD: Repositories & Factories

Repositories are used to re-create instances of objects from a data source.  Rather then placing the burden of retrieving data for object creation within our domain objects we should separate out that concern into "Repositories".  A repository is responsible for retrieving the data for our objects from our data store and re-creating instances of these objects using the data.  By abstracting the data retrieval operations out of our domain objects we provide greater flexibility within our domain.  We also ensure that our domain objects don't end up with knowledge of things they just shouldn't.   Since our objects aren't junked up with all the logic for data retrieval and object creation they can stay focused on representing our domain and the domain logic that makes up our applications.

After a repository has retrieved the data for a domain object it needs to re-create the domain object using the data.  There are times when the logic for performing the loading of the object from the data is appropriate within the repository, however, we'll often want to create a Factory object for this purpose.  A factory is responsible for the creation of objects.  The factory may be responsible for creating new object instances, as well as re-creating instances of objects from data.  By separating responsibility of object creation out of the repository we allow the repository to stay focused on its tasks of retrieving domain data out of the data store. 

Let's look at a quick example:

public class Customer {
   private string _firstName;
   private string _lastName;

   public string FirstName {
    get { return _firstName; }
    set { _firstName = value; }   
   }

   public string LastName {
    get { return _lastName; }
    set { _lastName = value; }   
   }
}

public class CustomerRepository {
   public Customer FindByID(int customerID) {
      IDataReader dataReader = ...;
      return new CustomerFactory().Create(dataReader);
   }
   public bool Save(Customer customer) {
      // save customer
   }
}

public class CustomerFactory {
  public Customer Create(IDataReader dataReader) {
    Customer customer = new Customer();
    if(dataReader.Read()) {
      customer.FirstName = dataReader["FirstName"].ToString();
      customer.LastName = dataReader["LastName"].ToString();
    }
    return customer;
  }
}

// UI Code
CustomerRepository repository = new CustomerRepository();
Customer customer = repository.FindByID(99);

// update fields/properties
...

repository.Save(customer);

By separating the responsibilities of data retrieval into our Repositories, and object creation into our Factories we allow our domain objects to stay focused on representing the domain.  We also allow our applications to become more de-coupled which allows us to more easily test our applications. 

 

# re: DDD: Repositories & Factories

Wednesday, August 11, 2004 6:14 AM by Shawn Oster    
I'm a Delphi developer and Object Persistence Frameworks (which this really is to my eye) are a big topic of discussion in the borland.public.delphi.oodesign newsgroup. I'd love to see more of your thoughts on Repositories. Especially in the following areas:

- Handling getting a list of customers, either all or by a search criteria (all customers that live in Colorado)

- Getting a customer by something other than an ID, say search by last name or address

- Handling the underlying repository magic, what is it backing into, how do you handle complex objects.

- How about aggregate objects, a customer that has an address object, does the customer repository instantiate an address repository internally?

In my own quest to make an Object Repositry / OPF those are the real world questions that you don't see any many answers for. Making that leap from theory to code is what I'm looking forward to hopefully seeing in future blogs.

# re: DDD: Repositories & Factories

Thursday, August 12, 2004 7:54 AM by Jiho Han    
I'm not sure whether this is limited to this repository idea but suppose that the customer object has an address object. And you call CustomerRepository.Save(customer). How will this handle the saving of the address object inside the customer object? Will it, in turn, call AddressRepository.Save(address) inside the CustomerRepository.Save method? If so, how can we make this an atomic transaction, preferably not involving Enterprise Services?

# re: DDD: Repositories & Factories

Thursday, August 12, 2004 11:43 AM by Steve    
Both very good questions. I'll try and formulate some thoughts around them as well as try and get some feedback from some others and blog whatever I come up with. Stay tuned...

# re: DDD: Repositories & Factories

Friday, August 13, 2004 6:11 AM by Kris    
I think the repository could support a strategy or specification interface when retrieving lists of entities.

The strategy interface could either specify the criteria, or perhaps the repository could query it directly to determine if an entity is a qualified match (eg. 'lives in colorado'.) Conceputally I like the latter approach, but it sucks in terms of performance. Its best to let the database do this sort of work, at which point your better off looking at a Query pattern I think.


# Repositories and aggregate objects...

Friday, August 20, 2004 7:04 AM by Jiho Han    
Repositories and aggregate objects...

# Udi's talking DDD

Saturday, September 18, 2004 12:48 PM by Steve Eichert    
Udi's talking DDD

Post a Comment

 
 
Prove you're not a spammer: 
7 + 6 =