Ho la seguente funzione pura (f2 e f3 sono pure):
class X {
def f1(arg: Type1): Type2 = {
val x = f2(arg)
val y = f3(x)
y
}
def f2...
def f3...
}
Ora, vorrei spostare f2 e f3 e posso pensare a 2 opzioni per farlo. Ti chiedi se uno è più funzionale dell'altro?
Opzione 1
Sposta f2 e f3 in un nuovo tratto e mescola il nuovo tratto in X in questo modo:
trait T {
def f2... // with implementation
def f3...
}
class X extends T {
def f1... // same implementation as earlier
}
Opzione 2
Sposta f2 e amp; f3 a un nuovo tratto (ma con l'implementazione in una classe) e la dipendenza iniettano il tratto in X in questo modo:
@ImplementedBy(classOf[T1Impl])
trait T {
def f2... // No implementation
def f3...
}
@Singleton
class TImpl extends T {
override def f2... // Implementation here
override def f3...
}
class X @Inject() (t: T) {
def f1 ... = {
val x = t.f2(arg)
val y = t.f3(x)
y
}
}
Una metà di me pensa che l'opzione 1 sia più funzionale (non coinvolge nessun bagaglio OO). L'altra metà (con la cronologia OOP / Java da cui provengo) urla che usare l'ereditarietà per la condivisione del codice è una cattiva idea. Soprattutto se X e T non sono correlati allora X estende T (X è a T) rende il codice look forzato.
L'uso della composizione rende il codice più naturale (X ha a T) ma è meno funzionale?