Implement a new feature with loose coupling - scala

trait paymentTasks{
def calculatePayment()
def getData()
}
class paymentcalculator{
override def calculatePayment() ={
//Implementation }
}
override defGetData() ={
}
}
How do I call the method to keep the code less dependent and don't want to use new keyword
class MyApp{
val payment = new paymentcalculator
//I don't want to instantiate like this wants this to be decoupled
}
Please suggest how do I implement this ,also new Changes in future can be done without changing existing code.Also,suggest if doing this functionally would be more effective

If you want compile-time selection then just put the code into an object
trait PaymentTasks {
def calculatePayment()
def getData()
}
object PaymentCalculator extends PaymentTasks {
def calculatePayment() = ???
def getData() = ???
}
class MyApp {
val payment = PaymentCalculator.calculatePayment()
}
If you want run-time selection than the best way is to use dependency injection and create the payment object at the top level and pass it down to the code that requires it.
object SimplePaymentCalculator extends PaymentTasks
object ComplexPaymentCalculator extends PaymentTasks
class MyApp {
def myImplementation(tasks: PaymentTasks) = {
val payment = tasks.calculatePayment()
}
val payment =
if (???) {
SimplePaymentCalculator
} else {
ComplexPaymentCalculator
}
myImplementation(payment)
}

Related

Is there any way to rewrite the below code using Scala value class or other concept?

I need to write two functions to get the output format and the output index for file conversion. As part of this, I wrote a TransformSettings class for these methods and set the default value. And in the transformer class, I created a new object of TransformSettings class to get the default values for each job run. Also, I have another class called ParquetTransformer that extends Transformer where I want to change these default values. So I implemented like below.
class TransformSettings{
def getOuputFormat: String = {
"orc"
}
def getOuputIndex(table: AWSGlueDDL.Table): Option[String] = {
table.StorageDescriptor.SerdeInfo.Parameters.get("orc.column.index.access")
}
}
class Transformer{
def getTransformSettings: TransformSettings = {
new TransformSettings
}
def posttransform(table: AWSGlueDDL.Table):Dateframe ={
val indexAccess = getTransformSettings.getOuputIndex(table: AWSGlueDDL.Table)
........
}
}
class ParquetTransformer extends Transformer{
override def getTransformSettings: TransformSettings = {
val transformSettings = new TransformSettings {
override def getOuputFormat: String = {
"parquet"
}
override def getOuputIndex(table: AWSGlueDDL.Table): Option[String] = {
table.StorageDescriptor.SerdeInfo.Parameters.get("parquet.column.index.access")
}
}
}
}
Is there a way to avoid creating a brand new object of TransformSettings in Transfomer class every time this is called?
Also is there a way to rewrite the code using Scala value class?
As #Dima proposed in the comments try to make TransformSettings a field / constructor parameter (a val) in the class Transformer and instantiate them outside
class TransformSettings{
def getOuputFormat: String = {
"orc"
}
def getOuputIndex(table: AWSGlueDDL.Table): Option[String] = {
table.StorageDescriptor.SerdeInfo.Parameters.get("orc.column.index.access")
}
}
class Transformer(val transformSettings: TransformSettings) {
def posttransform(table: AWSGlueDDL.Table): DataFrame ={
val indexAccess = transformSettings.getOuputIndex(table: AWSGlueDDL.Table)
???
}
}
val parquetTransformSettings = new TransformSettings {
override def getOuputFormat: String = {
"parquet"
}
override def getOuputIndex(table: AWSGlueDDL.Table): Option[String] = {
table.StorageDescriptor.SerdeInfo.Parameters.get("parquet.column.index.access")
}
}
class ParquetTransformer extends Transformer(parquetTransformSettings)
You don't seem to need value classes (... extends AnyVal) now. They are more about unboxing, not about life-cycle management. TransformSettings and Transformer can't be value classes because they are not final (you're extending them in class ParquetTransformer extends Transformer... and new TransformSettings { ... }). By the way, value classes have many limatations
https://failex.blogspot.com/2017/04/the-high-cost-of-anyval-subclasses.html
https://github.com/scala/bug/issues/12271
Besides value classes, there are scala-newtype library in Scala 2 and opaque types in Scala 3.

Is it possible to extend a method within an extended scala class?

Assume I have the following scala classes, is it possible to extend a function on SecondClass and add more code to it? (possibly chained to another function within the function i'd like to extend)
package io.gatling.http.check
class FirstClass {
def login() = {
exec(http("Login")
.post("anonymous/login")
.body(ElFileBody("rest/UserAnonymousLogin.json")).asJson
}
}
I would like to extend the login function with the following (.check(status is 200)
class SecondClass extends FirstClass {
def login() = {
.check(status is 200))
}
}
Is that possible?
The syntax you're looking for is
class X {
def go(a: Int) = ???
}
class Y extends X {
override def go(a: Int) = {
val u = super.go(a)
// do things with `u` and return whatever
}
}
You'll need to do a little refactoring to get your code in this shape. I envisage
class FirstClass {
def body = ElFileBody("rest/UserAnonymousLogin.json")
// stuff that calls `body`
}
class SecondClass {
override def body = super.body.check(status is 200)
// no need to redefine stuff as it's inherited from `FirstClass`
}
Given checks method accepts a variable number of HttpCheck, that is, HttpCheck*
def check(checks: HttpCheck*): HttpRequestBuilder
consider refactoring FirstClass to
class FirstClass {
def login(checks: HttpCheck*) = {
exec(http("Login")
.post("anonymous/login")
.body(ElFileBody("rest/UserAnonymousLogin.json")).asJson
.check(checks: _*)
)
}
}
Note how by default we pass no checks when calling (new FirstClass).login().
Now derived classes could pass in a checks to be performed like so
class SecondClass extends FirstClass {
def loginWithStatusCheck() = {
super.login(status is 200)
}
}
Note we are not actually overriding FirstClass.login here.
Another approach instead of overriding could be functional composition, for example, we break down the problem into smaller functions
val buildClient: String => Http = http(_)
val buildPostRequest: Http => HttpRequestBuilder = _.post("anonymous/login").body(ElFileBody("rest/UserAnonymousLogin.json")).asJson
val checkStatus: HttpRequestBuilder => HttpRequestBuilder = _.check(status is 200)
and then compose them
exec((buildClient andThen buildPostRequest andThen checkStatus)("Login"))
Now we can simply add further steps to the composition instead of worrying about class hierarchies and overriding.

How to access members of container class with same name? scala

I have something like this:
abstract class HaveData{
val data:String
}
class HD1 extends HaveData{
val data = "HD1 data"
}
class HD2 extends HaveData{
val data = "HD2 data"
object InnerHD extends HD1{
def prt = println(data)
}
}
I want to print "HD2 data" not "HD1 data", how to do that?
I may turn InnerHD to a class and provide data as a param but is there a better way?
For this kind of situations you can use a self-type, for this specific problem, you do not need to add a different type.
abstract class HaveData {
def data: String
}
class HD1 extends HaveData {
override val data = "HD1 data"
}
class HD2 extends HaveData { self => // Alias to this in the HD2 level.
override val data = "HD2 data"
object InnerHD extends HD1 {
def prt(): Unit = {
println(self.data)
}
}
}
(new HD2).InnerHD.prt()
// HD2 data
You can also use
def prt = println(HD2.this.data)

Play framework + Scala: Inject dependency using Action Composition

I'm setting up a Play! app for our API. This API encapsulates different services. I want to inject these services inside an action but only the ones required for that particular endpoint. Something like:
object Application extends Controller {
def index = (UsersAction andThen OrdersAction) {
// boom UsersService and OrdersService is available here
for {
users <- usersService.list
orders <- ordersService.list
} yield "whatever"
}
}
I've been playing with this idea and using ActionTransformers I'm able to transform the incoming Request to a request that has a given service, but I don't see how I can make that generic enough so I can compose these actions in an arbitrary order without create ActionTransformers for all the possible combinations of WrapperRequests.
Maybe action composition is not the best way to achieve this. I'm all ears.
Thank you
UPDATE:
To clarify, the code above is pseudocode, the ideal scenario, in which usersService and ordersService are made available to that scope (implicits? I don't know). If that's not possible, then whatever adds the less amount of noise of top of that sample that would work. Thanks
The closest I could get to your question is this:
def index =
new UsersAction with OrdersAction {
def body =
for {
users <- userService.list
orders <- orderService.list
} yield Ok("whatever")
}
The implementation is quite straight forward
trait CustomAction extends Action[AnyContent] {
def body: Future[Result]
def apply(request: Request[AnyContent]): Future[Result] = body
val parser = BodyParsers.parse.anyContent
}
trait UsersAction extends CustomAction {
val userService: UserService = ???
}
trait OrdersAction extends CustomAction {
val orderService: OrderService = ???
}
These are the other parts I used to get it to compile:
trait User
trait Order
trait UserService {
def list: Future[Seq[User]]
}
trait OrderService {
def list: Future[Seq[Order]]
}
You can inject by guice, spring or what you want.
Example for guice.
Just change the object to class:
class Application #Inject(userAction:UsersAction,ordersAction:OrdersAction) extends Controller {
def index = (UsersAction andThen OrdersAction) {
// boom UsersService and OrdersService is available here
for {
users <- usersService.list
orders <- ordersService.list
} yield "whatever"
}
}
You have to override in Global:
object Global extends GlobalSettings{
private lazy val injector = Guice.createInjector(new CommonModule)
override def getControllerInstance[A](clazz: Class[A]) = {
injector.getInstance(clazz)
}
}
class CommonModule extends AbstractModule{
protected def configure() {
bind(classOf[UsersAction]).to(classOf[UsersActionImpl])
bind(classOf[OrdersAction]).to(classOf[OrdersActionImpl])
}
}
In route file add # to controllers:
GET /service #controllers.Application.index

Events in Scala

I have a CategoryRepository class which implements several methods such that saves a category to database.
I also have an object Product that contains a list of categories.
What I want to do is to trigger an event that the Product object will listen to, and will update the product itself with the new data of its category.
In C# I know I can use delegates but I don't know if I can do something like this in Scala.
I don't want the CategoryRepository class to know the class Product so I won't call some method in Product that will update it through CategoryRepository.
My CategoryRepository class:
trait CategoryRepositoryComponentImpl extends CategoryRepositoryComponent {
val categoryRepository = new categoryRepositoryImpl
class CategoryRepositoryImpl extends CategoryRepository {
val dbRepository = CategoryDbRepository
def updateAttribute(id:String, request:UpdateCategoryItem): String = {
val cat = dbRepository.get(id)
cat.update(request)
dbRepository.save(cat)
}
}
}
The product repository looks the same as this category's repository.
Now I want to add a line after dbRepository.save(cat) that will trigger an event that will call the updateProduct() function within ProductRepository.
Please give an implementation example.
Thanks.
a (not so) basic implementation for an update channel based on events.
I took care to only generalize to the bare bone, as to give a hint to future evolution and code reuse.
Base infrastructure
We introduce an updates channel
//Listens for updates to A's and notifies interested listeners
class UpdateChannel[A] {
//simplified register
var listenMap: Map[A, Listening[A]] = Map()
//update call
def apply(a: A): Unit = listenMap.get(a).foreach(_.event(a))
//update call
def registerFor(a: value, listen: Listening[A]) = listenMap += (a, listen)
}
and a generic listener interested in corrisponding updates
//Listens to changes for type A
trait Listening[A] {
def event(upd: A): Unit
}
Application
Now we adapt the Repo Component to inject the channel
trait CategoryRepositoryComponentImpl extends CategoryRepositoryComponent {
val categoryRepository = new categoryRepositoryImpl
/************** NEW CODE HERE **************
* define a channel to send category updates
*******************************************/
def updateChannel: UpdateChannel[Category]
class CategoryRepositoryImpl extends CategoryRepository {
val dbRepository = CategoryDbRepository
def updateAttribute(id:String, request:UpdateCategoryItem): String = {
val cat = dbRepository.get(id)
cat.update(request)
dbRepository.save(cat)
//send the update to the channel
updateChannel(cat) //***************** << AND HERE
}
}
}
We also need to enable the product to event listening
//product must be listening to category updates
class Product(val category: Category) extends Listening[Category] {
def event(cat: Category) = ??? //strut your stuff here
...business stuff here too
}
Finally, here we put the ingredients together
//put the pieces together
def wireup() = {
//the channel
val catChan: UpdateChannel[Category] = new UpdateChannel[Category]
//the Repository component wired to the channel
val catRep = new CategoryRepositoryComponentImpl {
val updateChannel = catChan
}
//a nice cat
val myCat: Category = ???
//a nice prod with her nice cat
val p: Product = new Product(myCat)
//prod wants to know what happens to her cat
catChan.registerFor(myCat, p)
}
Remarks
we can make the Product independent of the whole framework by using refinement types
val product = new Product(myCat) with Listening[Category] {
def event(cat: Category) = ??? //strut your stuff here
}
a different solution would be to avoiding all the wirings and simply register a list of update closures in the RepositoryComponent
trait CategoryRepositoryComponentImpl extends CategoryRepositoryComponent {
val categoryRepository = new categoryRepositoryImpl
//public listeners, they should be encapsulated
var categoryUpdates: Seq[Category => Unit]
[...]
def updateAttribute(id:String, request:UpdateCategoryItem): String = {
val cat = dbRepository.get(id)
cat.update(request)
dbRepository.save(cat)
//send the update to the channel
categoryUpdates.foreach(_.apply(cat))
}
}
}
and the product needs only to add his own update function
catRep.categoryUpdates +:= (cat) => p.event(cat)
I think this would be more or less how it's done in C# with events and delegates.
When you define Event like this you'd have to use tuples (Event[(Any,EventArgs)] for instance) if you want to pass more than one parameter to the event listeners.
class Event[Arg] {
type L = Arg => Unit
private val listeners = scala.collection.mutable.ListBuffer.empty[L]
def +=(listener: L) {
listeners.append(listener)
}
def apply(arg: Arg) {
listeners.foreach(_(arg))
}
}
class CategoryRepository {
val event = new Event[String]
def fireEvent(data: String) {
event(data)
}
}
object Product {
def update(data: String) {
println(s"updating: $data")
}
}
object Main extends App {
val repo = new CategoryRepository()
repo.event += Product.update
repo.fireEvent("new data")
}