views:

22

answers:

1

I am looking for suggestions on how to map a single DTO class with a type discriminator to multiple domain classes.

I have my DTO:

public class FooData
{
    public Guid Id { get; set; }
    public string Name { get; set; }
    public string TypeDiscrim { get; set; }
}

public class FooDataRepository
{
    public List<FooData> GetAll() { /* select * from foo, basically */ }
}

I have a base domain object with a constructor dependency on a repository with a generic parameter:

public interface IFooDomain {}

public class FooDomainBase<B1> : IFooDomain where B1 : BarBase
{
    protected IBarRepository<B1> _barRepository;

    public FooDomainBase(FooData data, IBarRepository<B1> barRepository)
    {
        Id = data.Id;
        Name = data.Name;
        _barRepository = barRepository;
    }

    public virtual void Behavior1()
    {
        B1 thingToDoStuffWith = _barRepository.GetBar();
        /* do stuff */
    }

    public Guid Id { get; set; }
    public string Name { get; set; }
}

public class BarBase {}    

public interface IBarRepository<B1> where B1 : BarBase
{
    B1 GetBar();
}

Then I have a sample inheritor from my base domain object:

// There will be several of these
public class SuperFooDomain1 : FooDomainBase<SuperBar>
{
    public SuperFooDomain1(FooData data, IBarRepository<SuperBar> barRepository) : base(data, barRepository)
    { }

    public override void  Behavior1() { /* do something different than FooDomainBase */ }
}

public class SuperBar : BarBase { }

Now here's the kicker: I have a class that will consume a list of IFooDomain, which it gets from a repository. (IFooDomain is necessary because of the type parameter in FooDomainBase.)

// The FooManager class (not pictured) will use this to get all the 
public class FooRepository
{
    private FooDataRepository _datarepository;

    public FooRepository(FooDataRepository dataRepository)
    {
        _datarepository = dataRepository;
    }

    public List<IFooDomain> GetAll()
    {
        foreach (var data in _datarepository.GetAll())
        {
            // Convert FooData into appropriate FooDomainBase inheritor
            // depending on value of FooData.TypeDiscrim
        }
    }

}

Can I get the behavior in the comments above done with a DI framework? I'm guessing that I have to as the Service Locator pattern to return me an instantiated FooDomainBase inheritor, but I also need the constructor parameter of IBarRepository<SuperBar> resolved.

What frameworks can handle this sort of thing? If not out of the box, what do I need to extend?

I'm also open to critiques of the object hierarchy, since this may be pointing to a flaw in the design above.

+1  A: 

I'm not sure I was able to follow all the Foo/Bar stuff, but the standard solution to this kind of problem is by injecting one or more Abstract Factories into the consumer in question.

Define:

public interface IFooDomainFactory
{
    IFooDomain Create(string discriminator);
}

an inject it into FooRepository. When you implement IFooDomainFactory, you will need a way to get an IBarRepository<SuperBar>, but you can now define a new Abstract Factory that gives you that and inject it into the concrete FooDomainFactory.

You don't need any particular DI Container to do this, but they are all able to resolve dependencies like that.

Don't use Service Locator - it's an anti-pattern.

Mark Seemann
I read your blog post on the Service Locator earlier today and thought it was fantastically written. Sorry for the page of code - couldn't figure out a way to express the object hierarchy any more succintly.
Josh Kodroff
And I might add the ToC for the book you're working on has got me quite interested. It looks like a great way to present the topic.
Josh Kodroff
Thanks, I hope the answer was just a little bit helpful... The best Abstract Factory example I currently have is this: http://stackoverflow.com/questions/1926826/cant-combine-factory-di/1927167#1927167
Mark Seemann
Here's the thing I'm not getting: The FooManager class is going to get a heterogeneous list of a FooDomain descendents: SuperFooDomain1, SuperFooDomain2, etc. Can you elaborate on how I get from type discriminator to an instance of the appropriate FooDomain descendent? Is there going to be a big switch statement somewhere?
Josh Kodroff
I missed your last comment while I was posting the last one. I'll do some more homework and checkout that other question.
Josh Kodroff
Well, unless you can make each subtype an Abstract Factory itself (often a good idea), a big switch statement is more or less your only option. If you don't like the switch keyword, you can make a map from one to the other using a `Dictionary<string, Func<FooDomain>>`, but it amounts to the same thing...
Mark Seemann