为什么Date.new不调用initialize?

jst*_*jst 6 ruby inheritance date

我想创建Date的子类.

一个正常,健康,年轻的rubyist,由于Date的实现特性而没有受到干扰,将通过以下方式解决这个问题:

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
Run Code Online (Sandbox Code Playgroud)

并以最期望的方式继续使用它......

require 'my_date'

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

puts mdt.to_s
Run Code Online (Sandbox Code Playgroud)

......只有被出卖的事实,该日期::新方法实际上是一个别名日期::公民,不以往任何时候都调用初始化.在这种情况下,最后一段代码打印"2012-01-28"而不是预期的"2012-12-25".

亲爱的Ruby社区,wtf是这个吗?

是否有一些非常好的理由将别名设为new,这样它就会忽略初始化,因此,任何常识和对客户程序员心理健康的关注?

knu*_*nut 6

您可以定义initialize,但使用创建新实例new.new返回类的新实例,而不是结果initialize.

你可能会这样做:

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
Run Code Online (Sandbox Code Playgroud)

备注:@original_month和@original_day在此解决方案中不可用.以下解决方案扩展了日期,因此您可以访问原始月份和日期.对于正常日期,值将为零.

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
Run Code Online (Sandbox Code Playgroud)

但我会建议:

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
Run Code Online (Sandbox Code Playgroud)

要么

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
Run Code Online (Sandbox Code Playgroud)