Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do you do dependency injection with the Cake pattern without hardcoding?

Tags:

scala

I just read and enjoyed the Cake pattern article. However, to my mind, one of the key reasons to use dependency injection is that you can vary the components being used by either an XML file or command-line arguments.

How is that aspect of DI handled with the Cake pattern? The examples I've seen all involve mixing traits in statically.

like image 841
Bill Avatar asked Mar 02 '11 19:03

Bill


1 Answers

Since mixing in traits is done statically in Scala, if you want to vary the traits mixed in to an object, create different objects based on some condition.

Let's take a canonical cake pattern example. Your modules are defined as traits, and your application is constructed as a simple Object with a bunch of functionality mixed in

val application =     new Object extends Communications    with Parsing    with Persistence    with Logging    with ProductionDataSource application.startup 

Now all of those modules have nice self-type declarations which define their inter-module dependencies, so that line only compiles if your all inter-module dependencies exist, are unique, and well-typed. In particular, the Persistence module has a self-type which says that anything implementing Persistence must also implement DataSource, an abstract module trait. Since ProductionDataSource inherits from DataSource, everything's great, and that application construction line compiles.

But what if you want to use a different DataSource, pointing at some local database for testing purposes? Assume further that you can't just reuse ProductionDataSource with different configuration parameters, loaded from some properties file. What you would do in that case is define a new trait TestDataSource which extends DataSource, and mix it in instead. You could even do so dynamically based on a command line flag.

val application = if (test)   new Object     extends Communications       with Parsing       with Persistence       with Logging       with TestDataSource else   new Object     extends Communications       with Parsing       with Persistence       with Logging       with ProductionDataSource  application.startup 

Now that looks a bit more verbose than we would like, particularly if your application needs to vary its construction on multiple axes. On the plus side, you usually you only have one chunk of conditional construction logic like that in an application (or at worst once per identifiable component lifecycle), so at least the pain is minimized and fenced off from the rest of your logic.

like image 68
Dave Griffith Avatar answered Sep 19 '22 15:09

Dave Griffith