2014-05-14 14 views
22

Ho letto il section di Programmazione in Scala in cui è stato introdotto abstract override, ma sono ancora confuso da cosa si intenda esattamente con l'unione di questi modificatori. Il frammento di codice in cui questi modificatori viene utilizzato è incollato sotto:Perché è necessario "override astratto" non "override" da solo in subtrait?

trait Doubling extends IntQueue { 
    abstract override def put(x: Int) { super.put(2 * x) } 
} 

In particolare, mi sono confuso dalla finalità di abstract in questo caso, e perché non siamo in grado di raggiungere i risultati attesi in modo semplice con la parola chiave override. Se non includessimo una chiamata allo super, avremmo bisogno della parola chiave abstract? Perché o perché no? Sto cercando una spiegazione dettagliata di questa parola chiave combo per quanto riguarda i tratti impilabili.

risposta

18

La ragione è che il metodo della classe base è astratto

abstract class IntQueue { 
    def get(): Int 
    def put(x: Int) 
} 

Se si dovesse non mettere abstract sul tratto si finisce con la spiegazione che stavi cercando:

trait Doubling extends IntQueue { 
    override def put(x: Int) { super.put(2 * x) } 
} 
<console>:9: error: method put in class IntQueue is accessed from 
super. It may not be abstract unless it is overridden by a member 
declared `abstract' and `override' 
      override def put(x: Int) { super.put(2 * x) } 

Quindi, è necessario contrassegnare il metodo come abstract.

Ecco la "dall'altra parte" della equazione: se i metodi hanno implementazioni allora non è necessario marcare il metodo 's la trait come abstract:

abstract class IntQueue { 
    import collection.mutable._ 
     val q = Queue[Int]() 
     def get(): Int = { q.dequeue() } 
     def put(x: Int) = { q.enqueue(x) } 
    } 

Ora è necessario includere abstract

trait Doubling extends IntQueue { 
     /* Look Ma! no abstract here ! */ override def put(x: Int) { super.put(2 * x) } 
     } 
defined trait Doubling 
+1

_Thank you_. Per qualche ragione continuo a vedere esempi di tratti impilabili con 'override astratto ', ma mi sembra che i due concetti siano in realtà separati (anche se entrambi si basano su' super'). – Max

5

l'idea è che si tratta di una sostituzione incompleta - si vuole ancora richiedere l'attuazione finalmente concreta della caratteristica di fornire tale metodo, anche se si sta modificando che hypotheti comportamento del metodo cal In altre parole, il metodo che stai sovrascrivendo non è un'implementazione standalone completa. Fornisce un effetto simile a quello di method decorator in Python.

Per quanto posso ragionare, un metodo su un tratto è abstract override se e solo se si chiama super, ma si rompe l'incapsulamento aspettarsi che il cliente del codice di ispezionare l'attuazione del metodo per sapere che ha bisogno di una concreta implementazione. Pertanto, è necessario contrassegnarlo come abstract override per definire completamente l'interfaccia.

2

Una parte di late binding in scala traits messaggi; fornisce una spiegazione molto chiara; fornito sotto verbale (leggi lo full post per maggiori informazioni):

La classe base astratta ha fornito un'implementazione del metodo requestApproval. Questo è buono poiché il tratto più a sinistra chiama questo metodo. Cosa succede se il metodo della classe base è astratto?

abstract class ApprovalRequest { 
    def requestApproval() 
} 

Se cambiamo questo, si ottiene un messaggio piuttosto strana dal compilatore: errore: Metodo requestApproval in classe ApprovalRequest si accede da super.Esso non può essere astratta meno che non venga sovrascritto da un membro dichiarato abstract e override La combinazione di abstract e override dice al compilatore che l'attuazione definitiva del metodo sarà fornito dalla classe miscelatore nel tratto. Se aggiungiamo la parola chiave abstract ai metodi, non possiamo più utilizzare la nostra implementazione anonima di ApprovalRequest. Questo oggetto non può essere creato poiché i metodi di override astratti cercheranno un'implementazione di requestApproval e non ce n'è uno. Invece dobbiamo creare una nuova classe che estenda ApprovalRequest e implementa requestApproval. Quindi mescoliamo i tratti in un'istanza di quella classe.

class ApprovalDelegate extends ApprovalRequest { 
    override def requestApproval() { 
    println("and now we play the waiting game") 
    } 
} 

val adCampaign = new ApprovalDelegate with MarketingApprovalRequest 
    with FinanceApprovalRequest with ExecutiveApprovalRequest 

che ora darà l'output:

requesting approaval from executives 
requesting approval from Finance 
requesting approval from Marketing 
and now we play the waiting game