フレームワーク (8) - サブクラスでのメソッドのオーバーライドを禁止する #
C::M::App は、CGI::Application と同様、自分のクラスから継承されることを想定している
package MyClass;
use basee 'CGI::Minimal::App';
1;
んだが、一部メソッドは子クラスでのオーバーライド前提だし、一部メソッドはオーバーライドされたくないし、ということで、思案。他の言語みたいに attribute :final とか用意されてると
sub cannot_override :final {
}
とかするだけだし、そういうことを行うモジュール Attribute::Final もあるんだが、外部モジュール使うほどでもないし、attribute で実装しなくてもよかろう
# 子クラスの時だけ実行
unless ( ref $self eq __PACKAGE__ ) {
for my $method (@all_methods) {
next if .... ; # 親クラスのメソッドだったら何もしない
die 'You can NOT OVERRIDE method'
if ( grep {$_ eq $method} @not_override_methods );
}
}
まずは基本ということで、Class::Inspector 使ってみる
# Check methods that cannot override in Sub-Class
unless ( ref $self eq __PACKAGE__ ) {
my @not_override_methods = qw(
new run
_tt_obj _setup_http_headers _lvalue_method
);
for my $method ( @{Class::Inspector->methods(ref $self, 'expanded') || [[]]} ) {
next if $method->[1] eq __PACKAGE__;
die 'You can NOT OVERRIDE method ',__PACKAGE__,'::',$method->[2],' in ',$method->[1]
if ( grep {$_ eq $method->[2]} @not_override_methods );
}
}
続いて、Class::Inspector はコアモジュールではないので、使わない版
# Check methods that cannot override in Sub-Class
unless ( ref $self eq __PACKAGE__ ) {
my @not_override_methods = qw(
new run
_tt_obj _setup_http_headers _lvalue_method
);
{
no strict 'refs';
for my $method ( keys %{ref($self).'::'} ) {
next unless defined &{ref($self).'::'.$method};
die 'You can NOT OVERRIDE method ',__PACKAGE__,'::',$method,' in ',ref($self)
if ( grep {$_ eq $method} @not_override_methods );
}
}
}
タイムリーなことに、「どう書く?org 」で「メソッド名一覧の表示 」がお題になっているので、良さげな回答がでてきたらマネさせてもらおう
で、この実装だとコンストラクタ生成後にチェックするので、use した時点でチェクする方法考えた方がいいのかなぁ、とちょっと思った。new のしょっぱなにやっとけば同じかな