4

我有一些基类 A 有一个不会被覆盖的方法。

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

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

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!"

这是因为红宝石的特性。可以理解。

但是,如何强制基类方法dont_override_me不能被它的派生类覆盖?我在 java 中找不到像finalruby​​ 这样的关键字。在 C++ 中,可以将基类方法设置为非虚拟的,以便派生类无法覆盖它们。我如何在红宝石中实现这一点?

4

4 回答 4

6

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

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

它是定义 Ruby 的那些东西之一,所以与它对抗似乎有点毫无意义。如果有人重新定义了某些东西,所以它会严重损坏.. 那是他们的问题 ;-)

于 2009-04-02T07:28:40.870 回答
4

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

这也被打包成一个叫做“finalizer”的gem(gem install finalizer)

这利用了 method_added 回调并将新方法名称与您希望创建的方法列表进行比较final

于 2009-04-02T07:29:08.297 回答
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 的方法隐藏在一个 mixin 中,你会得到你想要的。B 的方法中任何不在 A 中的方法都将可用。已经在 A 中的方法不会被覆盖。

于 2010-08-09T18:47:36.817 回答
0

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

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'

警告:此示例不完整。如果你在子类中添加frozen_method了一个之前定义的方法,当这个方法在子类中被修改时,它将失去它的实现。

于 2016-10-25T19:02:18.557 回答