天然パーマです。

2019年っぽいPerl OOPらしい

2020年はどうなるかは置いておいて、2019年の最先端のPerl開発ボイラープレート - Qiitaを参考にする。

  • Moo
  • strictures
  • Function::Parameters
  • Type::Tiny

あたりを使う。

最近、Mooseを使ってデザインパターンを実装してみてるのでこれらを使って、Chain of Responsibilityパターンをなんとなく書いてみた。ちなみに以下のJava実装が解説を含めて分かりやすいので、ポーティングするような形で書いている。

Java実装との最大の差はInterfaceとか抽象クラスという概念がp5-Moose/Mooにはないことなんだけど、Roleがハマる時はRoleを使って表現している(といってもそのまま書き写すんじゃなくてPerlっぽい書き方で書いてるつもり)。

Support.pmJavaでは抽象クラスで書かれてたけど、今回は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と組み合わせて「かっこよく」書けるかな?って思った。以下、実装の全部。