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.