2012-12-28 19 views
9

Diciamo che abbiamo una classe con un 'nome' immobile:Semplice Scala getter/esclusione setter

class SuperFoo(var name: String) 

Se voglio ignorare questo, ad esempio aggiungere un po 'di blocco intorno alle chiamate:

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 
    } 
    } 
} 

quanto sopra genera un errore di compilazione:

super may be not be used on variable name 

Delle idee come attuare correttamente questo? (Escludere il setter getter & per aggiungere il blocco intorno a loro). Grazie!

+0

Il compilatore sembra pensare che io stia ignorando una variabile: se rimuovo l'istruzione super.name dal getter, ottengo questo messaggio di errore: "Nome variabile sovrascrivibile in classe SuperFoo di tipo String; nome del metodo non può sovrascrivere un mutabile" – Nikolaos

risposta

6

Qui è necessario fare riferimento direttamente al super setter/getter. Normalmente si dovrebbe scrivere qualcosa di simile a:

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 
    } 
    } 
} 

Tuttavia, se il setter compilerà senza alcun problema, il getter non sarà perché il compilatore vederlo come super.name.apply() (stringhe può ottenere questo metodo attraverso conversioni implicite).

vedo diverse opzioni: composizione

  1. favore nel eredità (un classico).
  2. Cambia il nome della variabile, rendilo privato e scrivi accessor nella super-classe (vedi sotto).
  3. Resort a riflessione/nome manuale vanguardo di ucangling.

andrò per l'opzione # 1, ma qui è il codice per l'opzione # 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: Ecco un'implementazione praticabile di opzione # 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

Grazie- stavo cercando di evitare l'opzione 2 e usare l'opzione 1 in qualche modo (l'opzione 3 è fuori questione a causa della riflessione). Tuttavia, l'opzione 1 non viene compilata anche se la proprietà non è una stringa, prova con Int e vedrai cosa intendo. Scalac pensa che tu stia cercando di sovrascrivere il campo "nome" per qualche ragione ... Qualche idea su come ottenere l'opzione 1 che funziona con, ad esempio, un Int? – Nikolaos

+0

Ho aggiunto la soluzione dell'opzione 1. Seguendo le linee guida GoF, il pattern di progettazione del decoratore consente di aggiungere un comportamento a un'implementazione esistente. – paradigmatic

Problemi correlati