2012-01-28 16 views
6

Chcę utworzyć podklasę Data.Dlaczego funkcja Date.new nie inicjalizuje połączenia?

Normalny, zdrowy, młody rubyist, unscarred przez idiosynkrazji realizacji data byłby przejść o tym w następujący sposób:

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 

i przejść do wykorzystania go w sposób najbardziej oczekiwanym ...

require 'my_date' 

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

puts mdt.to_s 

... tylko być dwukrotnie przeszedł przez fakt, że data :: nowa metoda jest właściwie aliasem Date :: cywilnego, który nie kiedykolwiek połączeń zainicjowany. W tym przypadku ostatni fragment kodu drukuje "2012-01-28" zamiast oczekiwanego "2012-12-25".

Droga społeczność Ruby, wtf to jest?

Czy jest jakiś bardzo dobry powód do aliasing nowy, tak że ignoruje zainicjować, a w rezultacie żadnego zdrowego rozsądku i szacunku dla zdrowia psychicznego klienta programisty?

+1

przez którego definicja "dobre"? –

+0

Jaka jest alternatywa? W przypadku wywołania funkcji civil from initialize przydzielony zostanie obiekt, którego nie potrzebujesz. – pguardiario

+0

Cóż, po prostu wydaje się semantycznie niewłaściwe, aby przydzielić i zainicjować obiekt w tej samej metodzie. Chodzi mi o to, że jeśli 'civil' jest de facto" nowym ", to dlaczego nie nazwać go' initialize' w końcu? Może to być czysta formalność w 'Date', ale pozwoli rozszerzyć klasę bez potrzeby wnikania w szczegóły jej implementacji. Zastanawiałem się więc, dlaczego decyzja o aliasie 'civil' na' new' mogła zostać podjęta? – jst

Odpowiedz

6

Definiujesz initialize, ale tworzysz nowe wystąpienie z new. new zwraca nowe wystąpienie klasy, a nie wynik initialize.

Można zrobić:

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 

Uwaga: @original_month i @original_day nie są dostępne w tym roztworze. Poniższe rozwiązanie wydłuża Data, dzięki czemu można uzyskać dostęp do oryginalnego miesiąca i dnia. W przypadku normalnych dat wartości będą zerowe.

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 

Ale polecam:

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 

lub

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

Dzięki za wspaniałą odpowiedź! Zakończyłem przeciążanie metody "new". Wydaje się bardzo dziwne, że alokacja i inicjalizacja obiektu odbywa się w jednej metodzie. – jst

+0

W definicji 'self.create' vars instancji są ustawiane w klasie, a nie w instancji. Użycie 'instance_variable_set' na wyniku' new' zadba o to; tylko upewnij się, że nadal zwracasz instancję. – Kelvin

Powiązane problemy