Reputation: 9734
I've implemented an Email service using the cake pattern. Here below is the EmailComponent
, which provides functionality for styling the email body:
trait EmailComponent {
def body: Body
trait Body {
def style(content Html): Html
}
}
trait DefaultEmailComponent extends EmailComponent {
def body = new DefaultBody
class DefaultBody extends Body {
views.html.email(content)
}
}
... and here is the EmailServiceComponent
that actually implements the Email service using an EmailComponent
:
trait EmailServiceComponent {
def emailService: EmailService
trait EmailService {
def sendEmail(from: String, recipients: Seq[String], subject: String, content: Html)
}
}
trait DefaultEmailServiceComponent extends EmailServiceComponent {
this: EmailComponent =>
def emailService = new DefaultEmailService
class DefaultEmailService extends EmailService {
def sendEmail(from: String, recipients: Seq[String], subject: String, content: Html) {
val htmlBody = body.style(content)
EmailHelper.sendEmail(from, recipients, Some(subject), (None, Some(htmlBody)))
}
}
The code above works fine... but I was surfing on the Internet when I came across MacWire. I read some documentation here and there and found really interesting, but to be honest I haven't fully understood how to use it and how it works. Having said that, how could I reimplement the example above with MacWire?
Upvotes: 0
Views: 1369
Reputation: 10677
Several things to consider:
One big difference is that the cake pattern in your example uses inheritance / class composition to satisfy dependencies and build the concrete instances, whereas with dependency injection you would mostly use delegation. It's up to you to decide how tightly coupled you want the classes to be.
There are limitations in MacWire to wiring when using traits defined
inside other traits. So your Default...
implementations would have to
go outside of their parent traits.
Upon a quick glance, it appears that MacWire cannot resolve concrete
implementations of a trait (unlike Guice, a well-established
dependency-injection framework for Java, where you could use
bindings and annotations for that). This means you'd have to use wire[DefaultEmailService]
instead of wire[EmailService]
.
There is no support for circular dependencies in MacWire. In the case above, you don't have them anyway: EmailServiceComponent depends on EmailService which in turn depends on EmailComponent.
So, with MacWire, your code would just be classes that use other classes, like
class DefaultEmailComponent extends EmailComponent { ... }
class DefaultEmailService(emailComponent: EmailComponent) extends EmailService { ... }
trait EmailServiceComponent {
def emailService: EmailService
}
class DefaultEmailServiceComponent(val emailService: EmailService)
extends EmailServiceComponent { ... }
lazy val emailC: EmailComponent = wire[DefaultEmailComponent]
lazy val emailSvc: EmailService = wire[DefaultEmailService]
lazy val emailSvcC: EmailServiceComponent = wire[DefaultEmailServiceComponent]
Upvotes: 2