Monday 16 February 2009

Factories and Repositories

In my last post I talked about entities, the domain objects that have an identity and a life. In this post I want to talk about the management of the lifetime of entities. We start at the beginning.

Creation of objects

Creation of objects could be very simple:
new RadioProgram(); // C#
or
RadioProgram.Create; //Delphi
But what when it is not that simple and there are a lot of extra dependencies and relations that should  be connected? We can use the Factory pattern for this purpose. When we use a Factory we use an object to create another object.

class RadioProgram
{
    public RadioProgram()
    {
    }

    public RadioStation { get; set; }
}

class RadioProgramFactory
{
    private RadioStation defaultStation = new RadioStation("DutchRadio");

    public RadioProgram CreateProgram()
    {
        RadioProgram program = new RadioProgram();
        program.RadioStation = this.defaultStation;
        return program;
    }
}

In the code above I create a RadioProgram which is only valid when there is a radio station assigned to it. (actually, normally this is not needed and added later, but I lack the fantasy to think of an original example). So to get a valid RadioProgram we will have to create a RadioProgramFactory and call the CreateProgram method.

Repositories

Now that we have a nice domain object, we need a place to store it. There are several places where we can store objects. We can store them in databases, in XML files, in binary streams and in a dozen of other places. But why should I (read the domain) should care about storage or persistency? We shouldn't care about it. In Domain Driven Design we create the domain with Persistence Ignorance in mind. The objects in the domain don't have to know when, where, why or even if they get persisted. The only thing we can/should do in the domain is to register the domain objects to Repositories.
A repository can be a big thing. We can use it to store objects, we can use it to find objects (in several ways) and we can use repositories to delete objects. But in the domain we won't actually do these things. Hmm. that is confusing.
OK, on one site I say that the domain should be able to talk to the repository. On the other side I say, the domain should not know anything about Persistence. To solve this problem we can say the following: The domain should create the definition (an interface) for the repository, it will tell what the domain expects from a repository.
Outside the domain we can have multiple implementations of a repository interface. With one implementation we talk to a legacy database, with another implementation we talk with a newly created database. During run-time we can say to the application which implementation it should use. This technique can be used for other things as well and is called Dependency Injection (although it has also some other names).
So how does a repository looks like? Here is an example of the interface that is in the domain:
public interface RadioProgramRepositoryInterface
{
    void Add(RadioProgram program);
    void Update(RadioProgram program);
    void Delete(RadioProgram program);

    RadioProgram GetProgram(string programName); // programName is the identifier in this case.
    List<RadioProgram> All(); // Get a list of all available RadioPrograms.
    List<RadioProgram> GetProgramQueueForStation(RadioStation aStation); // Get the program queue for a specific station.
}
So basically you can do anything in a repository that you can also do with a database, but the different is that you don't know what kind of database it is, it could also be an In-Memory stack or some files somewhere on the Internet. The last method is used to get a specific list of radio programs (programs that are queued for a specific station) This is a pretty easy selection, but it could be possible to get very complicated selections. In that case we can use Specifications or some kind of Query language. I will not go further into those topics, because they are to complicated to handle in short and I don't have any experience with them.

Dependency Injection

Before we can really use the persistent specific repositories we need to be able to find out which repository we need to use. This part of domain driven design can be difficult and it is easier said than done.
In my current project we maintain a list of interfaces and implementations that can be injected. (ie. RadioProgramRepositoryInterface - MemoryRadioProgramRepository, where the later is the implementation). The list is created at start-up time by a bootstrapper and this list is stored in a domain object called "World". This World object is a static object so every other object can reach it when necessary.
Of course this is not the best solution there is, but it works in our project. For more information about dependency injection you can read the following article: http://martinfowler.com/articles/injection.html
Closing words
Recently someone else also started a series about the basics of DDD, although is not very organized in the topic order, he is better organized in the topics itself. You can find his articles here (starting here)

No comments:

Post a Comment

Note: only a member of this blog may post a comment.