6

I have an abstract "Action" class, which has derived types of ActionAppointment, ActionCall, ActionEmail, and ActionLetter. I'm trying to write a function that will DRY up our service layer, so we're not writing CRUD calls 5 times anymore.

I have in our service layer some update logic (lots of other code removed for brevity):

private IServiceResponse UpdateAction<T>(T action, string originalActionStatus) where T : Action
{
        if (action.GetType() == typeof(Action))
        {
            _actionRepository.Update(action);
        }
        else if (action.GetType() == typeof(ActionAppointment))
        {
            _actionAppointmentRepository.Update(action as ActionAppointment);
        }
        else if (action.GetType() == typeof(ActionCall))
        {
            _actionCallRepository.Update(action as ActionCall);
        }
        else if (action.GetType() == typeof(ActionEmail))
        {
            _actionEmailRepository.Update(action as ActionEmail);
        }
        else if (action.GetType() == typeof(ActionLetter))
        {
            _actionLetterRepository.Update(action as ActionLetter);
        }
}

Unfortunately, how our repositories are setup, I have to use the specifically named repositories (ie. I can not update an ActionLetter through the _actionRepository even though it derives from Action)

I have been reading on different patterns, and it sounds like something similar to a Factory Pattern, but I can't see how to make it work.

Am I missing something stupid?

mandreko
  • 1,766
  • 2
  • 12
  • 24
  • 1
    You might consider the *Visitor* pattern (http://en.wikipedia.org/wiki/Visitor_pattern). – David R Tribble Jun 23 '11 at 20:14
  • 2
    Yes a factory pattern is a solution. Your Repositories must either have a common base class or implement an interface. They must all have an Update method that accepts the object typed as Action. The factory accepts the type as a parameter (in whatever form, name, type, enum if one is available) and returns the correct repository. That is pretty much it. Is there a specific point of confusion on how to implement the Factory? – Sisyphus Jun 24 '11 at 05:02
  • I'm unsure how to implement a factory pattern for this one, since IRepository is generic based on each domain model object. – mandreko Jun 25 '11 at 02:45
  • Sorry for slow response. A factory will not work with generics they are not type polymorphic. Generics are based on parametric polymorphism. It is a functional scope polymorphism. Factories require class scope polymorphism. Not sure I understand what you get out of this design beyond more type safety for basic updates etc? I use nHibernate it has an untyped Update anyway. I opt for a base Repository class with a common Update, and add some minimal typing - all my persisted objects have a single common base class, so i can't pass e.g net type as object that is not valid for persisting. – Sisyphus Jun 28 '11 at 08:42

2 Answers2

11

Can't you just write an overload of that method for each action type? Forget the <T> and typeof stuff - what you're doing is implementing a built-in language feature (method overloading) by hand, and in a fragile way too.

Matti Virkkunen
  • 63,558
  • 9
  • 127
  • 159
  • 3
    Yes, that is exactly what polymorphism and inheritance is all about. – David R Tribble Jun 23 '11 at 20:12
  • The code was previously written as a method for each Action type. I am just trying to DRY it up some, but I guess maybe I can DRY up some of the shared components, but have the specific repository code in each one. – mandreko Jun 25 '11 at 02:38
  • @Matt: Your if-else contraption isn't making the code any DRYer, that's for sure. – Matti Virkkunen Jun 25 '11 at 13:33
-2

Let's inverse the logic here:

abstract class Action {
    protected abstract Repository GetRepository();
    protected void Update(){
       this.GetRepository().Update(this);
    }
}

All you have to do is override the GetRepository in each of the deriving classes. For example:

class ActionAppointment : Action {
    protected override Repository GetRepository() {
        return _actionAppointmentRepository;
    }
}
linepogl
  • 9,147
  • 4
  • 34
  • 45