I am from Java background and new to functional paradigm as such, so please forgive and correct me I smell like OOP.
I have a trait names PaymentHandler
trait PaymentHandler {
def handleInit(paymentInfo: PaymentInfo, paymentConfig: PaymentConfig): Either[Future[WSResponse], Exception]
def handleComplete(paymentinfo: PaymentInfo, paymentConfig: PaymentConfig, clientToken: String): Future[Map[String, String]]
}
and
@Singleton
class PayPal extends PaymentHandler{....}
@Singleton
class BrainTree extends PaymentHandler{....}
Till here everything is Ok. but the problem comes when I want to have multiple PaymentGateways based on Payment method. Initially I wrote a PaymentHandlerFactory like
class PaymentHandlerFactory @Inject()(
paypal:PayPal,
braintree:BrainTree) {
def get(name:String): PaymentHandler = {
name match {
case "paypal" => paypal
case "bt" => braintree
case _ => null
}
}
}
and then use this PaymentHandlerFactory to get the PayPal object injected by guice. But somehow I felt this is not right way to do and I got onto companion objects. so this is the code I wrote then
object PaymentHandler {
@Inject
val paypal:PayPal = null
def apply(name:String): PaymentHandler = {
name match {
case "paypal" => paypal
case _ => null
}
}
}
Ofcourse this fails as it cannot Inject PayPal object. Now I have two questions in my mind.
The reason you cannot inject in companion object is because they are objects rather than classes. This means only a single instance exists and that is created by scala itself. If you want to do dependency injection, then the thing that requires the dependency must be created by the dependency injection framework. Therefore, you need to model your fatory using a class if you want to use guice.
I think what you did with your class PaymentHandlerFactory
is the pragmatic way and probably works in most cases. I would refrain from prematurely making this too generic.
If you want to make it a bit more guice-y, you could use their AssistedInject.