У меня есть класс Moo (se) [0] с рядом методов, которые имеют один и тот же тип «инструкции охраны» вверху. Вместо того, чтобы писать один и тот же код несколько раз, я решил, что могу поставить заявление в модификатор метода «до», и это работает отлично. Если этот класс не является подклассом, потому что тогда «перед защитой» никогда не вызывается.Moo (se), before и inheritance
package Foo;
use feature 'say';
use Moose;
has '_init' => (
is => 'rw',
isa => 'Bool',
default => 0
);
sub init {
shift->_init(1);
}
sub method {
say "in Foo::method";
}
before method => sub {
my $self = shift;
warn "==> Foo is not initialized\n" unless $self->_init;
};
package Bar;
use feature 'say';
use Moose;
extends 'Foo';
sub method {
say "in Bar::method";
}
package main;
use feature 'say';
my $foo = Foo->new;
say "foo the wrong way:";
$foo->method;
say "foo the right way:";
$foo->init;
$foo->method;
my $bar = Bar->new;
say "bar the wrong way:";
$bar->method;
Выход затем (с некоторыми добавлениями новых линий):
foo the wrong way:
==> Foo is not initialized
in Foo::method
foo the right way:
in Foo::method
bar the wrong way:
in Bar::method
Я предполагаю, что это поведение является, но есть ли (хороший) способ убедиться, что все подклассы также наследуют " перед "инструкцией модификатора метода/охраны? Или есть другой способ сделать это (я подозреваю, что это довольно распространенная конструкция). Обратите внимание, что исключение будет выведено в операторе real guard, но «предупреждение» намного проще в примере кода.
[0] Я предпочитаю использовать Moo, потому что я не использую никаких функций, требующих MOP, но оба Moo и Moose работают точно так же в этом вопросе.
Редактировать Использование ролей.
Если вы добавили Role
для этого (как предложено tobyink), и добавьте еще один способ сделать вещи немного более «реальной жизнью», я получаю своеобразный результат.
package Warning::NotInit;
use feature 'say';
use Moose::Role;
has '_init' => (is => 'rw', isa => 'Bool', default => 0);
before qw/ m1 m2/=> sub {
my $self = shift;
my $class = ref($self);
warn "==> $class is not initialized\n" unless $self->_init;
};
package Foo;
use feature 'say';
use Moose;
with 'Warning::NotInit';
sub init { shift->_init(1) }
sub m1 { say "in Foo::m1" }
sub m2 { say "in Foo::m2" }
package Bar;
use feature 'say';
use Moose;
extends 'Foo';
with 'Warning::NotInit';
sub m1 { say "in Bar::m1" }
package main;
use feature 'say';
При вызове не перекрытый метод в подклассе метод before
называется дважды.
my $bar = Bar->new;
say "bar the wrong way:";
$bar->m1;
$bar->m2;
Выход:
bar the wrong way:
==> Bar is not initialized
in Bar::m1
==> Bar is not initialized
==> Bar is not initialized
in Foo::m2
Почему она называется дважды?
Кроме того, я скажу, что ваша общая цель, кажется, чтобы убедиться, конкретный метод никогда не вызывает вызов объекта в неполном/несогласованном состоянии. Лучшим решением было бы убедиться, что ваш объект никогда не находится в этом состоянии. Напишите элемент «BUILD», который гарантирует, что ваш объект будет помещен в полное/согласованное состояние, как только он будет создан, и убедитесь, что ваши методы никогда не возвращают его в неполное/несогласованное состояние. – tobyink
В предыдущих итерациях кода я поместил весь установочный код в 'BUILD', но это привело к тому, что в подклассу все было сложно/беспорядочно. Конкретный класс представляет собой обертку Net :: Telnet с настройками для конкретной целевой платформы. Некоторым из подклассов необходимо настроить параметры в Net :: Telnet-> new (в родительском 'BUILD'), но по мере того, как подкласс' BUILD' вызывается после родителя, это было слишком поздно. – PerC