(我认为)我希望能够将基类实例转换为子类。我没有尝试将其作为角色来解决,但是子类化对我的情况更好。尝试覆盖方法时收到编译错误。这似乎与我在基类中使用子类有关。
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替代/超级糖后,我的代码似乎可以正常工作。我确实感觉我的代码没有通过气味测试,所以我将等待更好的答案,然后再将此更改发布为答案。
sub make_forecast {
my $self = shift;
# This removes existing Forecast attributes
Tank->meta->rebless_instance_back($self);
return $self->SUPER::make_forecast(@_);
}
编辑:看来我需要更多地描述我的项目。我的战车用诸如位置,名称,容量,当前水位等一般属性表示。我需要为特定日期创建预测。我觉得我希望所有这些都放在一个类中,但是我不想用预测的东西来污染标准的坦克类。静态或动态添加角色均不正确。我认为将一个坦克对象转换为带有预测对象的坦克是可行的,这就是造成本文所述错误的原因。我也喜欢使预测类与坦克分离,并从坦克实例使用委派给它,但这似乎有点笨拙。叹。我希望这有帮助。我仍在尝试为此找到最佳设计,并非常感谢任何想法。