(я думаю) Я хочу иметь возможность преобразовать экземпляр базового класса в подкласс.Я не пытался решать это как роль, но подклассы чувствуют себя лучше для моей ситуации.Я получаю ошибку компиляции при попытке переопределить метод.Похоже, это связано с моим использованием моего подкласса в базовом классе.
Tank.pm
package Tank;
use Moose;
use Tank::Forecast;
has id => (
isa => 'Int',
is => 'ro',
required => 1,
);
sub make_forecast {
my $self = shift;
my $date = shift;
return Tank::Forecast->meta->rebless_instance( $self, date => $date );
}
1;
Tank / Forecast.pm
package Tank::Forecast;
use Moose;
extends 'Tank';
has date => (
isa => 'Str',
is => 'ro',
required => 1,
);
has end_volume => (
isa => 'Num',
is => 'ro',
default => sub { rand() },
);
override 'make_forecast' => sub {
my $self = shift;
Tank->meta->rebless_instance_back($self);
return super();
};
1;
test.pl
use Tank;
my $tank = Tank->new( id => 1 );
$tank->make_forecast('2019-06-27');
print $tank->end_volume . "\n";
$tank->make_forecast('2019-06-28');
print $tank->end_volume . "\n";
Это приводит к ошибке компиляции:
You cannot override 'make_forecast' because it has no super method at /home/carl/perl5/perlbrew/perls/perl-5.16.3/lib/site_perl/5.16.3/i686-linux/Moose/Exporter.pm line 419
Moose::override('make_forecast', 'CODE(0x1871e70)') called at Tank/Forecast.pm line 25
require Tank/Forecast.pm at Tank.pm line 4
Tank::BEGIN at Tank/Forecast.pm line 0
eval {...} at Tank/Forecast.pm line 0
require Tank.pm at test.pl line 1
main::BEGIN at Tank/Forecast.pm line 0
eval {...} at Tank/Forecast.pm line 0
Compilation failed in require at Tank.pm line 4.
BEGIN failed--compilation aborted at Tank.pm line 4.
Compilation failed in require at test.pl line 1.
BEGIN failed--compilation aborted at test.pl line 1.
Я открыт для предложений получший способ спроектировать это и заставить его работать на самом деле.
РЕДАКТИРОВАТЬ: Мой код, кажется, работает, когда я удаляю Moose override / super sugar.Я чувствую, что мой код не проходит тест на запах, поэтому я подожду лучшего ответа, прежде чем опубликовать это изменение в качестве ответа.
sub make_forecast {
my $self = shift;
# This removes existing Forecast attributes
Tank->meta->rebless_instance_back($self);
return $self->SUPER::make_forecast(@_);
}
РЕДАКТИРОВАТЬ: Похоже, мне нужно описать мой проект больше.У меня есть танки, которые представлены с общими атрибутами, такими как местоположение, название, вместимость, текущий уровень и т. Д. Мне нужно создавать прогнозы на определенный день.Я чувствую, что хочу всего этого в одном классе, но я не хочу загрязнять стандартный класс танков вещами прогнозирования.Добавление роли, статически или динамически, было не совсем правильным.Я думал, что преобразование объекта резервуара в резервуар с прогнозируемым объектом будет работать, что и создало ошибку, описанную в этом посте.Я также поиграл с тем, чтобы сделать класс прогноза отдельным от танка и использовать делегирование ему из экземпляра танка, но это кажется немного более грубым.Вздох.Надеюсь, это поможет.Я все еще пытаюсь определить лучший дизайн для этого и действительно ценю любые идеи.