2010-04-28 13 views
3

Si j'ai quelques traits comme:trait mise en œuvre

trait A {...} 
trait B extends A{...} 
trait C1 extends B{...} 
trait C2 extends A{...} 

Je peux écrire la classe de deux façons (C1 et C2 ajoutent même fonctionnalité)

class Concrete1 extends B with C1 
class Concrete2 extends B with C2 

Quelle variante est meilleure (efficace)?

+1

Si C1 et C2 ajoutent la même fonctionnalité, pourquoi sont-ils séparés? – RoToRa

+0

Efficacité d'exécution pour l'appel de méthode? L'efficacité du programmeur pour la lisibilité? –

+0

@Mitch Blevins Efficacité d'exécution pour l'appel de méthode (et je pense à l'instant d'instanciation {1} de Concrete) @Différence dans l'héritage - Thay étend différentes classes mais a la même fonctionnalité f – Jeriho

Répondre

4

Ils sont identiques en termes de performances. Si vous écrivez un test comme celui-ci:

object Traits { 
    trait A { def a = "apple" } 
    trait B extends A { def b = "blueberry" } 
    trait C1 extends B { def c = "cherry" } 
    trait C2 extends A { def c = "chard" } 
    class Dessert extends B with C1 { } 
    class Salad extends B with C2 { } 
} 

et regardez le bytecode pour Dessert et Salad vous voyez

public Traits$Dessert(); 
    Code: 
    0: aload_0 
    1: invokespecial #29; //Method java/lang/Object."<init>":()V 
    4: aload_0 
    5: invokestatic #33; //Method Traits$A$class.$init$:(LTraits$A;)V 
    8: aload_0 
    9: invokestatic #36; //Method Traits$B$class.$init$:(LTraits$B;)V 
    12: aload_0 
    13: invokestatic #39; //Method Traits$C1$class.$init$:(LTraits$C1;)V 
    16: return 

public Traits$Salad(); 
    Code: 
    0: aload_0 
    1: invokespecial #29; //Method java/lang/Object."<init>":()V 
    4: aload_0 
    5: invokestatic #33; //Method Traits$A$class.$init$:(LTraits$A;)V 
    8: aload_0 
    9: invokestatic #36; //Method Traits$B$class.$init$:(LTraits$B;)V 
    12: aload_0 
    13: invokestatic #39; //Method Traits$C2$class.$init$:(LTraits$C2;)V 
    16: return 

Si vous allez ensuite et regardez les initialisations pour C1 et C2, ils sont les deux vides. Si vous regardez l'appel de méthode pour c, encore une fois, il s'agit d'une référence à celui défini dans C1 ou C2.

Cela se produit en raison de la façon dont les traits en couches sont interprétés. Vous pouvez les considérer comme une pile: chaque fois que vous ajoutez un "avec", toute la hiérarchie d'héritage est poussée sur la pile sauf que tout ce qui s'y trouve n'est pas ajouté à nouveau. Donc cela n'a pas d'importance si C2 a B ou non, puisque la classe Salad a déjà pris B car elle s'étend B.