如何在ruby中使基类方法不可覆盖?

时间:2009-04-02 07:22:49

标签: ruby oop override

我有一些基类A,其方法不能被覆盖。

class A
  def dont_override_me
    puts 'class A saying, "Thank you for not overriding me!"'
  end
end

另一个扩展A并尝试覆盖dont_override_me方法的B类。

class B < A
  def dont_override_me
    puts 'class B saying, "This is my implementation!"'        
  end
end

如果我实例化B并调用dont_override_me,将调用B类的实例方法。

b = B.new
b.dont_override_me # => class B saying, "This is my implementation!"

这是因为ruby的属性。可以理解的。

但是,如何强制基类方法dont_override_me不能被它的派生类覆盖?我在java的ruby中找不到像final这样的关键字。在C ++中,基类方法可以是非虚拟的,这样它们就不会被派生类覆盖。我如何在ruby中实现这一目标?

4 个答案:

答案 0 :(得分:6)

您可以通过挂钩更改事件并将其更改回来来实现,但对我来说似乎有点臭:

http://scie.nti.st/2008/9/17/making-methods-immutable-in-ruby

这是定义Ruby的那些东西之一,所以与它的斗争似乎有点无意义的imo。如果有人重新定义了某些东西,那么它就会破碎......这就是他们的问题; - )

答案 1 :(得分:4)

这是一种方法: http://www.thesorensens.org/2006/10/06/final-methods-in-ruby-prevent-method-override/

这也被打包成一个叫做“终结者”(gem install finalizer)的宝石

这会使用method_added回调,并将新方法名称与您希望制作final的方法列表进行比较。

答案 2 :(得分:1)

我建议:

class A #This is just as you've already defined it.
  def dont_override_me
    puts 'class A saying, "Thank you for not overriding me!"'
  end
end

module BehaviorForB
  def dont_override_me
    puts 'class B saying, "This is my implementation!"'        
  end

  def greet
    "Hello, Friend."
  end
end

class B < A
  include BehaviorForB
end

b = B.new
b.dont_override_me #=> class A saying, "Thank you for not overriding me!"
b.greet #=> Hello, Friend.

通过将B的方法隐藏在混合物中,你可以得到你想要的东西。 B的方法的任何方法都不在A中。已经在A中的方法将不会被覆盖。

答案 3 :(得分:0)

防止方法被子类覆盖的一种方法(但不推荐):

response = b'''{"products": [
    {
      "upc": "715187763623",
      "sku": 1833591,
      "salePrice": 13.99
    },
    {
      "upc": "8809269504036",
      "sku": 26220187,
      "salePrice": 16.99
    }
  ]
}'''

json_obj = json.loads(response.decode('utf-8'))

#print(json_obj["products"][0]["upc"])

for product in json_obj["products"]:
    print("upc:", product["upc"])
    print("sku:", product["sku"])
    print("salePrice:", product["salePrice"])
    print('---')
    cursor.execute("INSERT INTO bestb (sku, upc, salePrice) VALUES (%s,%s,%s)", (product["sku"], product["upc"], product["salePrice"]))

警告:此示例未完成。如果在子类中为先前定义的方法添加class Class def frozen_method(method) if class_variable_defined?(:@@__frozen_methods__) add= class_variable_get(:@@__frozen_methods__) | [method] class_variable_set(:@@__frozen_methods__,add) else class_variable_set(:@@__frozen_methods__,[method]) end class << self def inherited(child) def method_added(method) if class_variable_get(:@@__frozen_methods__).include? method send(:remove_method, method) error="Cannot change method #{method} because it's not overridde" raise TypeError, error end end end end end end class Foo def hello 'hello' end def foo 'foo' end frozen_method :foo end class Bar < Foo def foo 'new foo' end end #=> TypeError: Cannot change method foo because it's not overridde Bar.new.foo #=> 'foo' ,则在子类中修改此方法时,它将失去其实现。