2020年はどうなるかは置いておいて、2019年の最先端のPerl開発ボイラープレート - Qiitaを参考にする。
- Moo
- strictures
- Function::Parameters
- Type::Tiny
あたりを使う。
最近、Mooseを使ってデザインパターンを実装してみてるのでこれらを使って、Chain of Responsibilityパターンをなんとなく書いてみた。ちなみに以下のJava実装が解説を含めて分かりやすいので、ポーティングするような形で書いている。
Java実装との最大の差はInterfaceとか抽象クラスという概念がp5-Moose/Mooにはないことなんだけど、Roleがハマる時はRoleを使って表現している(といってもそのまま書き写すんじゃなくてPerlっぽい書き方で書いてるつもり)。
Support.pm。Javaでは抽象クラスで書かれてたけど、今回はRoleを使った。
package Support;
use Moo::Role;
use strictures 2;
use namespace::clean;
use Function::Parameters;
use Types::Standard qw/Str Object/;
has 'name' => (
is => 'ro',
isa => Str,
);
has 'next' => (
is => 'rw',
isa => Object,
);
requires 'resolve';
method support($trouble) {
if ( $self->resolve($trouble) ) {
$self->done($trouble);
} elsif ( $self->next ) {
$self->next->support($trouble);
} else {
$self->fail($trouble);
}
}
method done($trouble) {
print $trouble->to_string . " is resolve by [" . $self->name . "].\n";
}
method fail($trouble) {
print $trouble->to_string . " is cannot be resolved.\n";
}
1;
methodカッコイイ。ほんとはnextプロパティでSupportロールを実装しているクラスのインスタンス、ってのを指定したかったけど(Mooseだとできる)、Type::Standardにはそういうのなさそうなので(RoleNameっていうTypeならある)Objectを指定してる。
SpecialSupport.pmでは上記のRoleをwithして実装。
package SpecialSupport;
use Moo;
use strictures 2;
use namespace::clean;
use Function::Parameters;
use Types::Standard qw/Int/;
with 'Support';
has 'number' => (
is => 'ro',
isa => Int,
);
method resolve($trouble) {
return $trouble->number == $self->number;
}
1;
methodカッコイイ(2度目)。
Data::Validatorでやってたような、メソッドの引数の型チェックをType::Tinyと組み合わせて「かっこよく」書けるかな?って思った。以下、実装の全部。