views:

129

answers:

3

I have completely confused myself trying to design the necessary interfaces and abstracts to accomplish loading of domain entities that can be used by themselves as well as combined into an aggregate. Wow. That was a buzzword mouthful. Essentially, I have two objects that I would like to have base-type "load" functionality, but when these two objects are combined into one, I run into multiple inheritance.

So, I have my entities, which are like this (I'd draw

public class Account
public class Document
public class AccountDocument
{
    public Account Account{get;set;}
    public Document Document{get;set;}
}

Then, I have interfaces, like this:

public interface IAccountRepository
{
    Account Load(IDataContext context);
}

public interface IDocumentRepository
{
    Document Load(IDataContext context);
}

public interface IAccountDocumentRepository
{
    AccountDocument Load(IDataContext context);
}

Since both Account and Document can (and are) being derived from for other entities, I want to provide base functionality in the implementation so that I follow DRY.

public abstract class AccountRepositoryBase : IAccountRepository
{
    Account Load(IDataContext context)
    {
        //implementation for loading the Account from the context
    }
}

public abstract class DocumentRepositoryBase : IDocumentRepository
{
    Document Load(IDataContext context)
    {
        //implementation for loading the Document from the context
    }
}

This works fine for the individual Account and Document objects and their derivations, but the problem I can't seem to wrap my head around is how to handle the AccountDocument...

public class AccountDocumentRepository : AccountRepositoryBase, DocumentRepositoryBase
{
    //This is not possible, of course, due to multiple inheritance.
}

I know the solution can't be that hard, but I am completely tangled up and can't straighten out how I can provide the base "Load" functionality only once. Please help!

Thanks in advance.

+1  A: 

Wouldn't you want AccountDocumentRepository to implement IAccountDocumentRepository, and not inherit from AccountRepositoryBase and DocumentRepositoryBase?

Then you can always add AccountRepositoryBase and DocumentRepositoryBase properties to the IAccountDocumentRepository interface, or add them to the constructor of AccountDocumentRepository to ensure you have instances of both to do the work.

public class AccountDocumentRepository : IAccountDocumentRepository
{
    public AccountDocumentRepository(AccountRepositoryBase account, DocumentRepositoryBase document)
    {
        this.account = account;
        this.document = document;
    }

    public AccountDocument Load(IDataContext context)
    {
        //use your account & document instances here to create an AccountDocument.
    }

}
Aaron Daniels
+1  A: 

You can solve this by using composition instead of implementation inheritance - just let AccountDocumentRepository delegate to the the repository classes you've already written:

public class AccountDocumentRepository : IAccountDocumentRepository
{
    IAccountRepository accountRepository = new AccountRepositoryBase();
    IDocumentRepository documentRepository  = new DocumentRepositoryBase();

    public AccountDocument Load(IDataContext context) {
        Document document = this.documentRepository.Load(context);
        Account  account  = this.accountRepository.Load(context);
        return new AccountDocument(account, document);
    }
}

If you want the flexibility to substitute different concrete repositories, you can provide a constructor or properties that lets client code inject the IAccountRepository and IDocumentRepository.

There are several great StackOverflow questions that discuss the relative merits of implementation inheritance and composition and explain why we should strongly prefer composition. These are just a small selection of results from searching on "composition inheritance".

Jeff Sternal
Thank you. I think my confusion was stemming from the idea that this treats the Repository classes similar to entities, but this is what I was looking for.
AJ
A: 

You might want to look into the Inheritance Mapper Pattern from the Patterns Of Enterprise Application Architecture book.

and then make your own kind of Inheritance Repository Pattern based on it.

See:

  • Single Table Inheritance (278),
  • Class Table Inheritance (285),
  • Concrete Table Inheritance (293),
  • Inheritance Mappers (302).

http://martinfowler.com/eaaCatalog/

JW