views:

81

answers:

3

Is this a valid object design ? I have a domain object where i inject a service and call a verify method to update the state of the object and if all goes well send a confirmation message. The code looks like:

class Foo {
  String bar
  Service emailService


  public boolean verify() {
    bar = "foo"
        if(this.save()) {
            emailService.sendConfirmation()
        }
  }
}

Foo.get(1).verify()

Is it acceptable to call the emailService in such a away ? is there a design pattern that i can follow to use for such a situation.

Thank you - Ken

+5  A: 

There is nothing wrong with calling a service from an entity. There are, however, some problems concerning instantiating these services. If you follow this path, you have to somehow obtain an instance of a service during entity creation which is problematic.

Calling a constructor directly is obviously a bad idea (since it couples the entity to the service implementation).

Jimmy Bogard explained why injecting services into entities is a bad idea.

Instead of it, he suggested using 'double dispatch' (there were some debates if this name is appropriate) pattern to solve this problem. In this approach, a domain method callee provides a service implementation to the domain method. In your case it would look something like that:

class Foo {
  String bar    

  public boolean verify(Service emailService) {
    bar = "foo"
        if(this.save()) {
            emailService.sendConfirmation()
        }
  }
}

Foo.get(1).verify(new Service(...))

The last (but not least) option is to use Domain Events pattern. You can read about it on Udi Dahan's blog. In this approach entities are only responsible for publishing meaningful events which are subscribed by proper handlers. You can read full comparison of all these techniques on my blog.

Hope that helps

Szymon Pobiega
I would say that you should code to an interface here. That will make your entity testable and it will be easy to change the service if needed.**public bool verify(IConfirmationService emailService) ...**
Unmesh Kondolikar
I like very much the Domain Event Pattern and enjoyed reading Udi Dahan article and mostly the comments and his replies to them. I'm also of the opinion that the double dispatch technique should be used when the domain event technique doesn't solve the problem at hand. You also pointed out about the service locator that i think personally are evil as it gives a false sense of encapsulation. It also makes testing hell. Thank you for you insights and answers.
ken
+2  A: 

I'll usually send the confirmation from the place (action?) where from verify will be called. If the outcome of verify would be to send many confirmation emails then I'd probably have Foo generate and return ConfirmationMessages (a domain object) which would encapsulate all knowledge for a confirmation. The action would then be able to queue these messages for dispatch.

Having said that, if your Service is an Interface and you can inject mock for testing and the real one on production, then it looks good. Although I think it's best that domain objects hold knowledge and logic about themselves and not about systems (services) in another layer.

cherouvim
+1 This is the way to go in DDD
Jehof
+1 Verifying an object has nothing to do with sending emails. And imagine verifying multiple objects within a batch operation - you'd send an email for each one!
Vijay Patel
Wouldn't that be a weird API to have a verify method return a ConfirmationMessage object. What an API client expects is if the operation was successful or not. In what you're suggesting, when the verify operation fails would you return null value ?
ken
@ken. Yes it would be very weird. Probably it would be best to return a ValidationResult which would, between others, contain the ConfirmationMessage(s) but maybe this is an overkill. I generally prefer to construct the ConfirmationMessage(s) in the action which called the validation method. The problem is that if the validation requires the dispatch of many confirmation messages then you somehow have to communicate this from the entity back to the action.
cherouvim
Makes sense, I still prefer event based solution in this case though as it introduces more flexibility in handling the reponse, say multiple dispatch or simply delegating the action to the targeted component. Thank you for your insights.
ken
Yes, an event based solution seems the cleanest. Need to study and apply it some time :)
cherouvim
+2  A: 

Bad thing about this is that You lose isolation of Your domain model. Your domain model knows about email service which is pure infrastructure stuff.

It might be a good idea to introduce application service. Eventing pattern would do the trick too.

Arnis L.