2012-01-28 14 views
6

Voglio creare una sottoclasse di Data.Perché Date.new non chiama l'inizializzazione?

Un normale, sana, giovane rubyist, Unscarred per l'idiosincrasia di implementazione di Data sarebbe andare su questo nel modo seguente:

require 'date' 

class MyDate < Date 

    def initialize(year, month, day) 
    @original_month = month 
    @original_day = day 

    # Christmas comes early! 
    super(year, 12, 25) 
    end 

end 

e procedere ad usarlo nel modo più atteso ...

require 'my_date' 

mdt = MyDate.new(2012, 1, 28) 

puts mdt.to_s 

... solo per essere il doppio gioco per il fatto, che il metodo Date :: nuovo è in realtà un alias a Data :: civile, che non mai chiamata inizializzazione. In questo caso, l'ultima porzione di codice stampa "2012-01-28" anziché l'attesa "2012-12-25".

Caro Ruby-comunità, wtf è questo?

c'è qualche buona ragione per aliasing nuova, in modo che ignora inizializzare, e, di conseguenza, alcun senso e proposito comune per la salute mentale del programmatore del cliente?

+1

Con la cui definizione di "buono"? –

+0

Qual è l'alternativa? Se chiami Civil da inizializzare, hai assegnato un oggetto che non ti serve. – pguardiario

+0

Bene, sembra semplicemente semanticamente sbagliato allocare e inizializzare un oggetto nello stesso metodo. Voglio dire, se 'civil' è di fatto' nuovo', perché non farlo chiamare 'initialize' alla fine? Potrebbe essere una pura formalità in "Date", ma permetterà di estendere la classe senza la necessità di scavare nei dettagli dell'implementazione. Quindi, mi chiedevo, perché la decisione di alias 'civil' in' new' avrebbe potuto essere presa? – jst

risposta

6

Si definisce initialize, ma si crea la nuova istanza con new. new restituisce una nuova istanza della classe, non il risultato di initialize.

Si può fare:

require 'date' 

class MyDate < Date 

    def self.new(year, month, day) 
    @original_month = month 
    @original_day = day 

    # Christmas comes early! 
    super(year, 12, 25) 
    end 

end 

mdt = MyDate.new(2012, 1, 28) 

puts mdt.to_s 

Nota: @original_month e @original_day non sono disponibili in questa soluzione. La seguente soluzione estende la data, quindi è possibile accedere al mese e al giorno originale. Per le date normali, i valori saranno nulli.

require 'date' 

class Date 
    attr_accessor :original_month 
    attr_accessor :original_day 
end 

class MyDate < Date 

    def self.new(year, month, day) 

    # Christmas comes early! 
    date = super(year, 12, 25) 
    date.original_month = month 
    date.original_day = day 
    date 
    end 

end 

mdt = MyDate.new(2012, 1, 28) 

puts mdt.to_s 
puts mdt.original_month 

Ma mi raccomando:

require 'date' 

class MyDate < Date 

    def self.create(year, month, day) 
    @original_month = month 
    @original_day = day 

    # Christmas comes early! 
    new(year, 12, 25) 
    end 

end 

mdt = MyDate.create(2012, 1, 28) 

puts mdt.to_s 

o

require 'date' 

class Date 

    def this_year_christmas 
    # Christmas comes early! 
    self.class.new(year, 12, 28) 
    end 

end 

mdt = Date.new(2012, 1, 28).this_year_christmas 

puts mdt.to_s 
+0

Grazie per l'ottima risposta! Ho finito per sovraccaricare il metodo 'new'. Sembra molto strano, che l'allocazione e l'inizializzazione dell'oggetto avvengano in un unico metodo. – jst

+0

Nella vostra definizione 'self.create', le variabili di istanza vengono impostate sulla classe, non sull'istanza. L'uso di 'instance_variable_set' sul risultato di' new' si prenderà cura di questo; assicurati di restituire comunque l'istanza. – Kelvin

Problemi correlati