Is scala's cake pattern possible with parametrized components? - scala

Parametrized components work well with the cake pattern as long as you are only interested in a unique component for each typed component's, example:
trait AComponent[T] {
val a:A[T]
class A[T](implicit mf:Manifest[T]) {
println(mf)
}
}
class App extends AComponent[Int] {
val a = new A[Int]()
}
new App
Now my application requires me to inject an A[Int] and an A[String], obviously scala's type system doesn't allow me to extends AComponent twice. What is the common practice in this situation ?

I think the AComponent doesn't need to be parameterized itself. So loose the type parameter and change this into
trait AComponent {
val aInt: A[Int]
val aStr: A[String]
class A[T](implicit mf:Manifest[T]) {
println(mf)
}
}
class App extends AComponent {
val aInt = new A[Int]()
val aStr = new A[String]()
}
if you want to be able to provide instances for Int and String

Related

Is there a way to "program to interface" in scala

Is there a way to "program to interface" in scala?
I am new in Scala. I have a "trait" in scala and many classes extending that trait. I am looking for a way on how to use the interface instead of the class directly.
Currently, I am doing :
val clazz = new MyClass()
where MyClass is extended from a trait.
I am looking for a way to return the interface as an instance from the factory mathods for generating classes. Is there a way?
You can always just request the type of the interface:
val clazz: MyInterf = new MyClass()
If you really want to hide the implementation, one approach is to create a companion for the trait:
trait MyInterf {
...
}
class MyClass extends MyInterf {
...
}
object MyInterf {
def create: MyIntef = new MyClass()
}
// calling code
val impl = MyInterf.create

Invoking scala classes which extends traits during runtime

I am relatively new to scala so please bear me if I asked silly questions.
I have a requirement where I need to invoke a method run time.
I have a trait which is being extended by two classes
trait Animal {
def walk():DataFrame
}
This is extended by two classes.
class Dog(sparkSession: SparkSession) extends Animal {
def walk():DataFrame = {
.............
}
}
class Cat(sparkSession: SparkSession) extends Animal {
def walk():DataFrame = {
.............
}
}
Now from a config file I will get a list of these class names
Lets say like this
val animals = ["com.xy.Dog","com.xy.Cat"]
I need to invoke these classes and execute walk methods.
Can I do something like this?
animals.forEach{ animalString =>
val animalObject = Class.forName(animalString ).newInstance().asInstanceOf(Animal)
animalObject.walk
}
There are a few issues, let's take them one by one:
To build a list in scala you need to do:
val animals = List("com.xy.Dog", "com.xy.Cat")
The forEach method is actually foreach, so there's a small typo. Finally, when you call the newInstance you should get the appropriate constructor before that, otherwise it will use the default one.
animals.foreach { animalString =>
val animalObject = Class.forName(animalString)
.getConstructor(classOf[DataFrame]) // Get the constructor for a DataFrame argument
.newInstance(dataframe) // Pass the dataframe instance
.asInstanceOf[Animal]
animalObject.walk
}
I've made a couple of small changes to the code for you to see it working. You can run the app to see the output:
class Dog extends Animal {
def walk(): Unit = { println("I'm a dog.") }
}
class Cat extends Animal {
def walk(): Unit = { println("I'm a cat.") }
}
object AnimalTest extends App {
val animals = List("com.xy.Dog", "com.xy.Cat")
animals.foreach { animalString =>
val animalObject = Class.forName(animalString)
.newInstance()
.asInstanceOf[Animal]
animalObject.walk
}
}
Note that I've removed the constructor arguments here to easily build instances. The rest is about the same. I hope this helps you.

Abstracting the Database client in the cake pattern

I am trying to create an abstraction for a SearchService using the Cake pattern. This is what I have currently:
trait SearchServiceComponent{
val searchService:SearchService
trait SearchService{
def searchForSomething(..):List[String]
def updateIndex(..):Boolean
}
}
Lets say I have a DbSearchServiceComponent and LuceneSearchServiceComponent as follows:
trait DbSearchServiceComponent extends SearchServiceComponent{
class DbSearchService extends SearchService{
//Initialize the db client
//Implement all the trait methods
}
}
Similarly...
trait LuceneSearchServiceComponent extends SearchServiceComponent{
class LuceneSearchService extends SearchService{
//Initialize the lucene client
//Implement all the trait methods
}
}
The issue I have with the above snippet is that
I have initialized instances of lucene client and the db client in the Service implementations.
Ideally I would want to "mix-in" a "Client" base type that can be either a Db client or a Lucene client but I am pretty confused as to how to inject a polymorphic client type here.
Can somebody point out how I may be able to refactor the code so that I can inject different versions of the client to my implementations of the SearchService trait?
Not sure if I interpret your question correctly, but that's how you could use the cake pattern for this:
trait SearchServiceComponent {
val searchService: SearchService
trait SearchService {
def searchForSomething(...): List[String]
def updateIndex(...): Boolean
}
}
trait DbSearchServiceComponent extends SearchServiceComponent {
override val searchService = new SearchService {
// Initialize client, implement methods
}
}
trait trait LuceneSearchServiceComponent extends SearchServiceComponent {
override val searchService = new SearchService {
// Initialize client, implement methods
}
}
and upon instantiation:
val myLucenceApp = new Whatever with LuceneSearchServiceComponent
val myDbApp = new Whatever with DbSearchServiceComponent
where Whatever would typically be something along the lines of
class Whatever { this: SearchServiceComponent =>
// ... use `searchService` and do lots of other things
}

Scala Dependency Injection with Cake Pattern

I've been following this article which describes how to achieve dependency injection in Scala via the Cake Pattern:
http://jonasboner.com/real-world-scala-dependency-injection-di/
I'm kind of new to Scala and I admit some of it went over my head, so far I've got the following working:
// Setup the component and interface
trait AccountRepositoryComponent {
val accountRepository: AccountRepositoryInterface
trait AccountRepositoryInterface {
def message: String
}
}
// An implementation
trait MyAccountRepositoryComponent extends AccountRepositoryComponent {
object AccountRepository extends AccountRepositoryInterface {
def message: String = "Hello"
}
}
// Object to configure which implementations to use and retrieve them
object ComponentRegistry extends MyAccountRepositoryComponent {
val accountRepository = AccountRepository
}
// Example service using the above
object AccountService {
val repo = ComponentRegistry.accountRepository
def say: String = repo.message
}
println(AccountService.say)
What I'm failing to understand is how I would now pass in a fake repository to Account Service, say to change the output to "Test" rather than "Hello"?
There are various ways this could be modified to achieve a workable result, depending on what counts as a workable result for your situation. I'll go through a simpler possibility here.
First, the ComponentRegistry needs to become a trait, so it can be mixed in to the AccountService:
// Trait to configure which component implementations to use and retrieve them
object ComponentRegistry extends MyAccountRepositoryComponent {
val accountRepository = AccountRepository
}
// Example service using the above
object AccountService extends ComponentRegistry {
def say: String = accountRepository.message
}
println(AccountService.say)
This should print "Hello" as before. To set up a test case, add the following:
// Test implementation
trait TestAccountRepositoryComponent extends AccountRepositoryComponent {
object AccountRepository extends AccountRepositoryInterface {
def message: String = "Test"
}
}
// trait to configure test component implementations
trait TestComponentRegistry extends TestAccountRepositoryComponent {
val accountRepository = AccountRepository
}
Now we can set up a service that uses the test components:
// Example service using the above
object AccountService extends TestComponentRegistry {
//val repo = ComponentRegistry.accountRepository
def say: String = accountRepository.message
}
println(AccountService.say)
This should print "Test".
Note that you would probably want your AccountService to define its functionality in terms of other mixins/traits, which would expect the appropriate components to be available (layered into the "cake"), but wouldn't know which implementation was in use. Eg:
trait CustomerApi {
self: AccountRepositoryComponent => // Expects an implementation of AccountRepositoryComponent to be mixed in
def say: String = accountRepository.message
}
Now the method say is implemented without knowing what version of AccountRepository it will interact with, but knowing one must be provided (checked at compile time). So we can write:
object AccountService extends CustomerApi with ComponentRegistry
object TestAccountService extends CustomerApi with TestComponentRegistry
Calling println(AccountService.say) will generate "Hello", while calling println(TestAccountService.say) will generate "Test".
This post provides a succinct example of that (followed by an interesting alternative).

Abstract fields for dependency injection

In Scala, is there there anything wrong with using the below method of dependency injection.
// Define an interface
trait FileStorage {
def readFile(filename:String):OutputStream
}
// And an implementation
class S3FileStorage extends FileStorage {
def readFile(filename:String):OutputStream = ???
}
// Define our service as a trait with abstract fields that need to be
// injected in order to construct. All implementation details go here.
trait FileHTTPServer {
val fileStorage:FileStorage
def fetchFile( session:Session, filename:String ) = ???
}
Now we wire things up
// Wire up a concrete file service that we actually use in code
// No implementation details should go here, we're simply wiring up a FileHttpServerl
// An entire project could be wired up this way in a central location if desired.
object S3FileHttpServer extends FileHTTPServer {
val fileStorage = new S3FileStorage
}
// We could also do this anonymously
val myHttpServer = new FileHttpServer {
val fileStorage = new S3FileStorage
}
// Or create a mocked version for testing
val mockedHttpServer = new FileHttpServer {
val fileStorage = mock[FileStorage]
}
Obviously the Cake pattern provides more flexibility (particularly around self-types), however for simpler use cases this has much less boilerplate, while still providing compile time checking and a clean unambiguous interface.
Yes, this is absolutely fine approach. And yes, sometimes you can use constructor injection, nothing wrong with that too. But with constructor injection you have to propagate your dependencies manually, while with cake pattern your dependencies are propagated automatically via self-type annotations. So for big projects constructor injection actually lead to more boilerplate than cake pattern, especially at the construction site (where you create all your objects and set up dependencies between them).
However, what you have presented is not full-fledged cake pattern. In real cake pattern there is an additional layer around business logic classes, so-called components, and you do not wire up logic classes directly but components instead.
trait FileStorageComponent {
def fileStorage: FileStorage
trait FileStorage {
def readFile(filename: String): OutputStream
}
}
trait S3FileStorageComponent extends FileStorageComponent {
val fileStorage = new S3FileStorage
class S3FileStorage extends FileStorage {
def readFile(filename: String): OutputStream = ???
}
}
trait FileHttpServerComponent {
self: FileStorageComponent =>
val fileHttpServer = new FileHttpServer
class FileHttpServer {
def fetchFile(session: Session, filename: String) = ???
}
}
// Wiring
object S3FileHttpServer extends FileHttpServerComponent with S3FileStorageComponent
// Anonymous
val server = new FileHttpServerComponent with S3FileStorageComponent
// Mocking
object TestFileHttpServer extends FileHttpServerComponent with FileStorageComponent {
val fileStorage = mock[FileStorage]
}
In this approach there are more boilerplate in traits definitions, but in return you have greater flexibility and very clear dependency management on the use place. For example, here is how program entry point in one of my projects looks like:
object Main
extends MainUI
with DefaultActorsManagerComponent
with DefaultPreferencesAccessComponent
with DefaultModelComponent
with DefaultMainWindowViewComponent
with DefaultMainWindowControllerComponent
with MainWindowReporterComponent
with DefaultClientActorComponent
with DefaultResponseParserActorComponent
with DefaultArchiverActorComponent
with DefaultMainWindowAccessActorComponent
with DefaultUrlParserComponent
with DefaultListenerActorComponent
with DefaultXmlPrettifierComponent
All main program components are in one place. Pretty neat IMO.