Reputation: 9103
I have two Java classes Foo
and Bar
(from a third part library which I am not supposed to change) and they are not related by any interface
, abstract
or any other classes.
However they have signature methods like
public String createToken(String id)
that is the same in both classes, and another method which is quite similar apart from the object type returned in the list:
for the class Foo
=> public List[FooItem] getItems(String id)
and for the class Bar
=> public List[BarItem] getItems(String id)
In my Scala code I am using these two classes in methods that are basically duplicated. For example:
def getFooItems(foo: Foo, id: String): Vector[FooItem] = {
foo.createToken(id)
foo.getItems(id).asScala.toVector
}
def getBarItems(bar:Bar, id: String): Vector[BarItem] = {
bar.createToken(id)
bar.getItems(id).asScala.toVector
}
As you can see the code is pretty much the same but for a lots of methods (and more than just two classes) it becomes quite a sort of huge duplicated code.
Is there any way with Scala to generalise the code to get a sort of:
def getItems[A,B](someClass:A, id: String): Vector[B] = {
someClass.createToken(id)
someClass.getItems(id).asScala.toVector
}
Or the duck typing the only way?
Upvotes: 2
Views: 103
Reputation: 105
how about this, use trait and class only
trait TokenManager {
def createToken(id: String): String
}
class FooToken extends TokenManager {
override def createToken(id: String) = Foo.createToken(id)
}
class BarToken extends TokenManager {
override def createToken(id: String) = Bar.createToken(id)
}
def getToken(tokenManager: TokenManager, id: String): String = tokenManager.createToken(id)
Upvotes: 0
Reputation: 1239
I suggest you try out typeclass pattern.
First you have to define interface common for Foo
and Bar
:
trait Tokenable[T, TItem] {
def createToken(t: T, id: String): String
def getItems(t: T, id: String): List[TItem]
}
Then you need to define implementation for every class you want to apply it to:
object FooBar {
class Foo {
def createToken(id: String): String = ???
def getItems(id: String): List[FooItem] = ???
}
class Bar {
def createToken(id: String): String = ???
def getItems(id: String): List[BarItem] = ???
}
class FooItem
class BarItem
implicit object FooTokenable extends Tokenable[Foo, FooItem] {
def createToken(f: Foo, id: String) = f.createToken(id)
def getItems(f: Foo, id: String) = f.getItems(id)
}
implicit object BarTokenable extends Tokenable[Bar, BarItem] {
def createToken(b: Bar, id: String) = b.createToken(id)
def getItems(b: Bar, id: String) = b.getItems(id)
}
}
Now you can use it in any method with implicit Tokenable
parameter:
import FooBar._
def getItemsAsVector[T, TItem](t: T, id: String)
(implicit tok: Tokenable[T, TItem]) = {
tok.createToken(t, id)
tok.getItems(t, id).toVector
}
val vector = getItemsAsVector(new Foo, "my_id")
Upvotes: 3