2012-12-28 14 views
9

Lassen Sie uns sagen, dass wir eine Klasse mit einer Eigenschaft ‚Name‘ haben:Einfache Scala Getter/Setter Überschreibung

class SuperFoo(var name: String) 

Wenn ich möchte dies außer Kraft zu setzen, um zB eine Verriegelung um die Anrufe hinzufügen:

class SubFoo(n: String) extends SuperFoo(n) { 
    val lock = new ReentrantLock 
    override def name(): String = 
    { 
     lock.lock 
     try { 
     super.name 
     } finally { 
     lock.unlock 
     } 
    } 
    override def name_=(arg: String): Unit = { 
    lock.lock 
    try { 
     super.name = arg 
    } finally { 
     lock.unlock 
    } 
    } 
} 

Das erzeugt über einen Übersetzungsfehler:

super may be not be used on variable name 

Irgendwelche Ideen, wie man das richtig umzusetzen? (d. h., überschreiben Sie den Getter & Setter, um eine Sperre um sie hinzuzufügen). Vielen Dank!

+0

der Compiler scheint, ich bin überschreibt eine Variable zu denken: wenn ich die super.name Anweisung aus dem Getter entfernen, erhalte ich diese Fehlermeldung: „zwingende Variablennamen in der Klasse SuperFoo vom Typ String; Methodenname nicht wandelbar außer Kraft setzen kann“ – Nikolaos

Antwort

6

Hier müssen Sie direkt auf die Super-Klasse Setter/Getter beziehen. Normalerweise sollte man so etwas schreiben:

class SubFoo(n: String) extends SuperFoo(n) { 
    val lock = new ReentrantLock 
    override def name(): String = 
    { 
     lock.lock 
     try { 
     super.name() 
     } finally { 
     lock.unlock 
     } 
    } 
    override def name_=(arg: String): Unit = { 
    lock.lock 
    try { 
     super.name_=(arg) 
    } finally { 
     lock.unlock 
    } 
    } 
} 

Wenn jedoch die Setter ohne Probleme kompilieren, wird der Getter nicht, weil der Compiler als super.name.apply() sehen wird (Strings können diese Methode durch implizite Conversions).

Ich sehe mehrere Möglichkeiten:

  1. Favor Komposition der Vererbung (ein Klassiker).
  2. Ändern Sie den Variablennamen, machen Sie es privat und schreiben Sie Accessor in der Super-Klasse (siehe unten).
  3. Rücksortierung nach/manueller Name Umangeln Voodoo.

ich für Option # 1 gehen würde, aber hier ist der Code für die Option # 2:

class SuperFoo(private var nameVar: String) { 
    def name: String = nameVar 
    def name_=(arg: String): Unit = nameVar = arg 
} 

class SubFoo(n: String) extends SuperFoo(n) { 
    val lock = new ReentrantLock 
    override def name(): String = 
    { 
     lock.lock 
     try { 
    super.name 
     } finally { 
     lock.unlock 
     } 
    } 
    override def name_=(arg: String): Unit = { 
    lock.lock 
    try { 
     super.name = arg 
    } finally { 
     lock.unlock 
    } 
    } 
} 

EDIT: Hier ist eine praktikable Umsetzung der Option # 1:

trait Foo { 
    def name: String 
    def name_=(arg: String): Unit 
} 

class SimpleFoo(var name: String) extends Foo 

class LockedFoo(foo: Foo) extends Foo { 
    val lock = new ReentrantLock 
    def name(): String = 
    { 
     lock.lock 
     try { 
     foo.name 
     } finally { 
     lock.unlock 
     } 
    } 
    def name_=(arg: String): Unit = { 
    lock.lock 
    try { 
     foo.name = arg 
    } finally { 
     lock.unlock 
    } 
    } 
} 
+0

Danke- Ich habe versucht, Option 2 zu vermeiden und verwende deine Option 1 irgendwie (Option 3 kommt aufgrund der Reflektion nicht in Frage). Allerdings Option 1 nicht einmal kompilieren, wenn die Eigenschaft nicht eine Zeichenfolge ist, versuchen Sie mit Int und Sie werden sehen, was ich meine. Scalac denkt, dass du aus irgendeinem Grund versuchst, das 'Name'-Feld zu überschreiben ... Irgendwelche Ideen, wie man Option 1 mit zB einem Int arbeiten kann? – Nikolaos

+0

Ich habe Option 1 Lösung hinzugefügt. Gemäß den GoF-Richtlinien ermöglicht das Decorator-Entwurfsmuster, einer vorhandenen Implementierung ein Verhalten hinzuzufügen. – paradigmatic