Scipion
Scipion

Reputation: 11888

Combining Dependency Injections and inheritance with Play 2.5

In my process of migrating an App from 2.4 to 2.5 (and getting rid of all the static references), I have done the following:

class Generic @Inject()(implicit val mat: Materializer, cache: CacheApi, wsClient: WSClient, configuration: play.api.Configuration) 
{ ... }

@Singleton
class Concrete1 @Inject() (gw:Generic) { ... }

@Singleton
class Concrete2 @Inject() (gw:Generic) { ... }

To use it, I do inject Concrete1/2 with an instance of Generic. It works, but after having seen several other examples about that on the web it doesn't seem quite correct.

I am thinking about modifying it like this :

    abstract class Generic(cache: CacheApi, wsClient: WSClient, configuration: play.api.Configuration) 
    { ... }

    @Singleton
    class Concrete1(cache: CacheApi, wsClient: WSClient, configuration: play.api.Configuration) 
       extends Generic(cache, wsClient, configuration) { ... }

    @Singleton
    class Concrete2(cache: CacheApi, wsClient: WSClient, configuration: play.api.Configuration) 
       extends Generic(cache, wsClient, configuration) { ... }

Then in order to be able to do : @Inject() (c1:Concrete1, c2:Concrete2) I guess I need them to be modules as defined by : https://www.playframework.com/documentation/2.5.x/ScalaDependencyInjection#Programmatic-bindings ? What makes more sense to do here ?

Upvotes: 3

Views: 222

Answers (1)

millhouse
millhouse

Reputation: 10007

I'd actually disagree with your "doesn't seem quite correct" statement.

I'd argue that your first example more closely reflects the composition over inheritance philosophy that has become accepted as a more maintainable way to build software.

Without knowing anything about your Concrete or Generic classes, it's hard to say more, but I would be very surprised if the latter, inheritance-based structure, was easier to properly unit test, whereas it would be trivial to mock a Generic and inject it to test Concrete classes.

Other benefits:

  • less noisy/repetitive declaration
  • less tied to Play framework (no need for a module definition)
  • future flexibility (for when your concrete classes share a second "common" class)

Upvotes: 1

Related Questions