2013-10-15 12 views
6

Diciamo che ho una classe con alcune variabili "statiche". Voglio che una sottoclasse di quella classe sia in grado di sovrascrivere quelle variabili senza influenzare la classe originale. Questo non è possibile utilizzare variabili di classe, dal momento che tali sembra essere condivisi tra sottoclassi e superclassi:Come sovrascrivere una variabile in una sottoclasse Ruby senza influire sulla superclasse?

class Foo 
    @@test = "a" 

    def speak; puts @@test; end 
end 

class Bar < Foo 
    @@test = "b" 
end 

Bar.new.speak 
# b 

Foo.new.speak 
# b 

non è possibile utilizzando le costanti sia:

class Foo 
    TEST = "a" 

    def speak; puts TEST; end 
end 

class Bar < Foo 
    TEST = "b" 
end 

Bar.new.speak 
# a 

Foo.new.speak 
# a 

I metodi definiti nella superclasse ignora costanti nella sottoclasse.

La soluzione ovvia è quella di definire i metodi per le variabili che devono essere "override":

class Foo 
    def test; "a"; end 
end 

Ma che si sente come un hack. Credo che questo dovrebbe essere possibile usando le variabili di classe e che probabilmente sto sbagliando. Per esempio, quando ho sottoclasse Object (che è ciò che accade per impostazione predefinita):

class Foo < Object 
    @@bar = 123 
end 

Object.class_variable_get(:@@bar) 
# NameError: uninitialized class variable @@bar in Object 

Perché non è @@bar impostato su Object come se fosse nella mia Bar < Foo esempio di cui sopra?


Per riassumere: come sovrascrivere una variabile in una sottoclasse senza influire sulla superclasse?

risposta

5

costanti classe non ciò che si vuole, non vi resta che utilizzare in modo diverso:

class Foo 
    TEST = "a" 

    def speak 
    puts self.class::TEST 
    end 
end 

class Bar < Foo 
    TEST = "b" 
end 

Bar.new.speak # => a 
Foo.new.speak # => b 
+0

Modificato il testo della risposta per avere più senso, spero che non ti dispiaccia. Questo mi sembra il modo più corretto per me, quindi accetto la risposta. – Hubro

+0

@Codemonkey La tua domanda originale riguardava le variabili, non le costanti. Sebbene Ruby ti permetta di sovrascrivere le costanti, riceverai avvertimenti per farlo e sarà confusionario per chiunque legga il tuo codice. La risposta di Denis è il modo corretto di implementare le variabili per classe. – Max

+1

@Max: Se leggi l'intera domanda, sarà chiaro che tutto ciò che sto cercando è un modo per sovrascrivere un * valore * legato a una classe in una sottoclasse - non è importante se si tratta di variabili o costanti. Sono d'accordo che "variabile" potrebbe essere stata una scelta scadente di parole. L'uso di costanti come questa mi sembra più diretto e intuitivo rispetto alla definizione di lettori di attributi di meta-classe. Non ho ricevuto alcun avviso dalla definizione di costanti in sottoclassi con lo stesso nome delle costanti nelle loro superclassi (come nell'esempio di questa risposta) – Hubro

2

Il modo corretto (IMHO) è utilizzare i metodi, perché in questo modo si utilizza l'ereditarietà e il dispacciamento virtuale, proprio come si desidera.

Le variabili di classe sono condivise lungo la gerarchia, non in alto. Ecco perché @@bar non è disponibile in Object.

+0

+1 per la spiegazione sulle variabili di classe – Hubro

4

aggiungere una variabile alla classe stessa (come nel caso della classe, piuttosto che una variabile di classe):

class Foo 
    @var = 'A' 

    class << self 
    attr_reader :var 
    end 

    def var 
    self.class.var 
    end 
end 

class Bar < Foo 
    @var = 'B' 
end 

Foo.var # A 
Foo.new.var # A 
Bar.var # B 
Bar.new.var # B 
+0

Mi piace questo approccio anche se! –

+0

Funziona anche così: 'Foo.var # A' e' Bar.var # B' –

Problemi correlati