メソッドのオーバーライドを禁止してみたい(というかjavaでいうところのfinalをやりたい)と思ったので、いろいろ調べてみたところ、クラスの定義に関するフックmethod_addedとinheritedを使うとできそうなので、コードを書いてみました。

  • method_addedでメソッドの定義が行われると、そのメソッドを削除して例外を発生させる
    • 継承してmethod_addedを上書きすると上記チェックを回避できてしまう
  • inheritedで例外を発生させて継承を禁止する
    • inheritedのチェックだけだと、同一クラスの再定義でメソッドを上書きできてしまう

method_addedでremove_methodをすると、上書き前のメソッドも削除されてしまうのが、ちょっと不便ですね。追加前をフックできるといいのですが。。。

module FinalClass
  class << self
    def included(base)
      base.extend ClassMethods
    end
  end
  
  module ClassMethods
    def method_added(name)
      remove_method name
      raise TypeError, "You cannot define a new method!"
    end
    
    def inherited(subklass)
      raise TypeError, "You cannot define a subclass!"
    end
  end
end

class A
  include FinalClass
end


ま、実務で使うかどうかといわれるとわかりませんが・・・。

■ 参考

本記事は上記2記事を足して割った感じです。


freezeの利用も検討しましたが、いろいろと抜け穴ができてしまったので断念しました。

  • クラスをfreezeすると、メソッドの再定義もできなくなる
  • ただし、いくつか抜け道がある
    • 継承するとメソッドのオーバーライドが可能(inheritedでサブクラスをfreezeするアプローチもあるが・・・)
    • クラスをdupするとメソッドのオーバーライドができてしまう(cloneはfreezeを引き継ぐので問題ない)

Posted by あかさた
最近のエントリ
最近の読書メモ