【问题标题】:Override ruby constant in subclass so inherited methods use new constant instead of the old?覆盖子类中的 ruby​​ 常量,以便继承的方法使用新常量而不是旧常量?
【发布时间】:2012-10-25 10:09:26
【问题描述】:

在 Ruby 中,有没有一种方法可以“覆盖”子类中的常量,使得从子类调用继承的方法会导致该方法使用新常量而不是旧常量?例如:

class SuperClass
  CONST = "Hello, world!"
  def self.say_hello
    CONST
  end
end

class SubClass < SuperClass
  override_const :CONST, "Hello, Bob!"
end

SuperClass.say_hello # => "Hello, world!"
SubClass.say_hello   # => "Hello, Bob!"

如果没有,是否有办法代替这样做?

class SuperClass
  CONST = "Hello, world!"
  def self.say_hello
    CONST
  end
end

SubClass = SuperClass.clone
SubClass.send(:remove_const, :CONST)
SubClass.const_set(:CONST, "Hello, Bob!")

SubClass.say_hello # => "Hello, Bob!"

注意:我在 irb 中尝试了我的第二个示例,它似乎可以正常工作,只是在我克隆类后类方法似乎无法访问 CONST:

irb(main):012:0> SubClass.say_hello
NameError: uninitialized constant Class::CONST
        from (irb):4:in `say_hello'
        from (irb):12
        from C:/Ruby193/bin/irb:12:in `<main>'

【问题讨论】:

    标签: ruby


    【解决方案1】:

    我通过简单地在子类中重新定义常量,然后在方法中将其引用为实例方法中的self.class::CONST 和类方法中的self::CONST 来完成此操作。在您的示例中:

    class SuperClass
      CONST = "Hello, world!"
      def self.say_hello
        self::CONST
      end
    end
    
    class SubClass < SuperClass
      CONST = "Hello, Bob!"
    end
    
    SubClass.say_hello #=> "Hello, Bob!"
    

    【讨论】:

    • 这似乎是一个很好的方法。不幸的是,它不适用于我的情况,因为我想要覆盖其常量的类是我不想弄乱的外部库(gem)的一部分。
    • @Ajedi32 所有类都开放修改,包括内部库或外部gem。您可以使用class String /*blah blah*/ end 来修改字符串类等。
    • @texasbruce 是的,但在这种情况下我不想修改 gem;我只想在 gem 中克隆一个类,它有一个稍微修改过的常量。覆盖类本身的方法或常量会弄乱 gem 的内部工作,这不是我想要做的。
    • 我们要重写常量,以便它们对 gem 中常量的直接引用应该使用重写的常量定义。我还没想出办法。
    • @Jazz 不完全是。我希望宝石的行为与现在完全一样。这是我想要更改其行为的子类,而不是超类,我想这样做,而不必在我的代码库中复制大量 gem 的代码。 (例如,如果 gem 在它的 20 个方法中引用 CONST,我不想覆盖所有 20 个方法,复制它们的所有代码,这样我就可以将它们更改为引用 self::CONST。)
    【解决方案2】:

    你可以在父类中引用这样的常量:

    对于实例方法:self.class::CONST

    对于 self 方法:self::CONST

    class SuperClass
      CONST = "Hello, world!"
      def print_const
        puts self.class::CONST
      end
    
      def self.print_const
        puts self::CONST
      end
    
    end
    
    class SubClass < SuperClass
      CONST = "Hello, Bob!"
    end
    
    SubClass.new.print_const #=> "Hello, Bob!"
    SubClass.print_const #=> "Hello, Bob!"
    

    【讨论】:

      【解决方案3】:

      如果您有幸能够更改基类,请考虑将需要更改的“常量”封装在基类中的类方法中,并根据需要在子类中覆盖它们。这消除了父类和子类常量之间混淆的可能性。例如,如下所示:

      class SuperClass
        CONST = "Hello, world!".freeze
      
        def self.const
          CONST
        end
      
        def self.say_hello
          const
        end
      end
      
      class SubClass < SuperClass
        CONST = "Hello, Bob!".freeze
      
        def self.const
          CONST
        end
      end
      
      SubClass.say_hello #=> "Hello, Bob!
      

      【讨论】:

      • 如果可以做到这一点,为什么要保留常量而不直接使用方法?
      • 它可以是一种文档形式。
      猜你喜欢
      • 2011-03-11
      • 1970-01-01
      • 2016-11-11
      • 1970-01-01
      • 2016-08-16
      • 2022-01-24
      • 1970-01-01
      • 2012-04-14
      • 2010-10-20
      相关资源
      最近更新 更多