メソッドのオーバーライドを禁止してみたい(というか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を引き継ぐので問題ない)