Как сделать метод базового класса не перезаписываемым в ruby? - PullRequest
2 голосов
/ 02 апреля 2009

У меня есть некоторый базовый класс 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 не быть переопределенным его производными классами? Я не смог найти ключевое слово типа final в java для ruby. В C ++ методы базового класса могут быть сделаны не виртуальными, так что они становятся не перекрываемыми производными классами. Как мне добиться этого в ruby?

Ответы [ 4 ]

6 голосов
/ 02 апреля 2009

Вы можете сделать это, подключив событие change и вернув его обратно, но мне это кажется немного вонючим:

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

Это одна из тех вещей, которая как бы определяет Ruby, поэтому борьба с ним кажется немного бессмысленной. Если кто-то что-то переопределяет, так что это ужасно ломается .. в этом их проблема; -)

4 голосов
/ 02 апреля 2009

Вот способ сделать это: http://www.thesorensens.org/2006/10/06/final-methods-in-ruby-prevent-method-override/

Это также было упаковано в гем под названием "финализатор" (финализатор установки камня)

Это использует обратный вызов method_added и сравнивает имя нового метода со списком методов, которые вы хотите сделать final.

1 голос
/ 09 августа 2010

Рекомендую:

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, которых еще нет в A, будет доступен. Методы, которые уже есть в A, не будут переопределены.

0 голосов
/ 25 октября 2016

Один из способов предотвратить переопределение метода подклассом (но не рекомендуется):

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 для ранее определенного метода в подклассе, когда этот метод будет изменен в подклассе, он потеряет свою реализацию.

...