Perl日記

日々の知ったことのメモなどです。Perlは最近やってないです。

Strategyパターン

読んでる。

Head Firstデザインパターン ―頭とからだで覚えるデザインパターンの基本

Head Firstデザインパターン ―頭とからだで覚えるデザインパターンの基本


復習がてら第1章のStrategyパターンをPerlのMouseでやってみた。
(Mouse::RoleをJavaのinterfaceとして使っているけれど、これは正確な使い方ではないらしい)
Moose::RoleはJavaのInterfaceなんかじゃない - 北海道苫小牧市出身のPGが書くブログ


Github
https://github.com/rightgo09/perl-headfirst-designpattern

動きのテスト

test.pl

use strict;
use warnings;

use MallardDuck; # マガモ
use ModelDuck;   # 鴨模型

my $duck;

$duck = MallardDuck->new;

$duck->perform_quack; #=> ガーガー
$duck->perform_fly;   #=> 飛んでいます!!
$duck->swim;          #=> すべての鴨は浮かびます。おとりの鴨でも!

$duck = ModelDuck->new;

$duck->perform_fly; #=> 飛べません
use FlyRocketPowered;
$duck->fly_behavior(FlyRocketPowered->new);
$duck->perform_fly; #=> ロケットで飛んでいます!

clientの親クラス

Duck.pm

package Duck {
  use Mouse;

  has quack_behavior => (
    is => 'rw',
    does => 'QuackBehavior',   # 鳴き声interfaceを持つ
    handles => {
      perform_quack => 'quack', # perform_quackでquackメソッドを呼び出す
    },
  );

  has fly_behavior => (
    is => 'rw',
    does => 'FlyBehavior',  # 飛行interfaceを持つ
    handles => {
      perform_fly => 'fly',  # perform_flyでflyメソッドを呼び出す
    },
  );

  no Mouse;

  __PACKAGE__->meta->make_immutable;

  sub display {
    die "This method is abstract method!";
  }

  sub swim {
    print "すべての鴨は浮かびます。おとりの鴨でも!\n";
  }
}

1;

clientの継承クラス

MallerdDuck.pm

package MallardDuck {
  use Mouse;

  extends 'Duck';  # Duckクラスを継承
  use Quack;
  use FlyWithWings;

  sub BUILD {
    my $self = shift;
    $self->quack_behavior(Quack->new);  # 鳴き声の振る舞いを設定
    $self->fly_behavior(FlyWithWings->new);  # 飛行の振る舞いを設定
  }

  # 親の抽象メソッドをオーバライドして具象化
  sub display {
    print "本物のマガモです\n";
  }
}

1;

ModelDuckも同様の継承と実装。

interface

QuackBehavior.pm

package QuackBehavior { # 鳴き声interface
  use Mouse::Role; # interfaceにRoleを使う

  requires 'quack'; # quackのメソッド定義を強制
}

1;

interfaceの実装

Quack.pm

package Quack {
  use Mouse;

  with 'QuackBehavior';  # 鳴き声interface

  # 鳴き声interfaceの実装
  sub quack {
    print "ガーガー\n";
  }
}

1;

FlyBahaviorについても同様のinterface。

Strategyパターンまとめ

Mo[ou]seを使うと、Roleとかdoesとかで簡単に振る舞いをカプセル化できることに今更分かった。
OOPすごい。