Featured image of post 第2回-MooX::Cloneでモンスターを量産しよう - mass-producing-monsters

第2回-MooX::Cloneでモンスターを量産しよう - mass-producing-monsters

MooX::Cloneを導入してclone()メソッドを追加!ベースモンスターを1体作れば、あとはclone()で量産し放題。コードが劇的に短くなる魔法を体験しよう。

@nqounetです。

「PerlとMooでモンスター軍団を量産してみよう」シリーズの第2回です。

前回の振り返り

前回は、10体のスライムをnew()で作ろうとして、コードが冗長になる問題を確認しました。

同じパラメータを10回書くのは面倒ですし、修正も大変でしたね。今回は、この問題をMooX::Cloneで解決します。

シリーズ全体の目次は以下をご覧ください。

MooX::Cloneとは

MooX::Cloneは、Mooクラスにclone()メソッドを追加するCPANモジュールです。clone()を呼ぶと、既存オブジェクトをコピーして新しいオブジェクトを作れます。

インストールはcpanmで簡単にできます。

1
cpanm MooX::Clone

clone()でオブジェクトをコピーする

まずは基本的な使い方を見てみましょう。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
#!/usr/bin/env perl
# 言語: perl
# バージョン: 5.36以上
# 依存: Moo, MooX::Clone(cpanmでインストール)

use v5.36;

package Monster {
    use Moo;
    use MooX::Clone;  # clone()メソッドを追加

    has name    => (is => 'ro', required => 1);
    has hp      => (is => 'rw', required => 1);
    has attack  => (is => 'rw', required => 1);
    has defense => (is => 'rw', required => 1);
    has color   => (is => 'rw', default => '緑');

    sub show_status ($self) {
        say "【" . $self->name . "】HP:" . $self->hp
            . " 攻撃:" . $self->attack
            . " 防御:" . $self->defense
            . " 色:" . $self->color;
    }
}

# ベースとなるスライムを1体作成
my $base_slime = Monster->new(
    name    => 'スライム',
    hp      => 10,
    attack  => 3,
    defense => 2,
);

# clone()でコピーを作成
my $slime2 = $base_slime->clone;
my $slime3 = $base_slime->clone;

$base_slime->show_status;  # 【スライム】HP:10 攻撃:3 防御:2 色:緑
$slime2->show_status;      # 【スライム】HP:10 攻撃:3 防御:2 色:緑
$slime3->show_status;      # 【スライム】HP:10 攻撃:3 防御:2 色:緑

use MooX::Clone;を追加するだけで、clone()メソッドが使えるようになります。

ベースとなるスライムを1体作り、$base_slime->cloneでコピーを作成しています。コピーしたオブジェクトは元のオブジェクトと同じ属性値を持っています。

10体のスライムを3行で量産!

前回30行かかっていたコードが、たった3行になります。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
#!/usr/bin/env perl
# 言語: perl
# バージョン: 5.36以上
# 依存: Moo, MooX::Clone(cpanmでインストール)

use v5.36;

package Monster {
    use Moo;
    use MooX::Clone;

    has name    => (is => 'ro', required => 1);
    has hp      => (is => 'rw', required => 1);
    has attack  => (is => 'rw', required => 1);
    has defense => (is => 'rw', required => 1);
    has color   => (is => 'rw', default => '緑');

    sub show_status ($self) {
        say "【" . $self->name . "】HP:" . $self->hp
            . " 攻撃:" . $self->attack
            . " 防御:" . $self->defense
            . " 色:" . $self->color;
    }
}

# ベーススライムを1体作成
my $base_slime = Monster->new(
    name    => 'スライム',
    hp      => 10,
    attack  => 3,
    defense => 2,
);

# 10体のスライムをclone()で量産(たった3行!)
my @slimes = map { $base_slime->clone } 1..10;

say "=== スライム軍団 ===";
for my $slime (@slimes) {
    $slime->show_status;
}

map { $base_slime->clone } 1..10という1行で、10体のスライムが生成されます。

100体でも1000体でも、数字を変えるだけです。これが「量産」の快感です。

修正も簡単

スライムのHPを10から15に変更したい場合も、ベースを1箇所変えるだけで済みます。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
# ベースのHPを15に変更すると...
my $base_slime = Monster->new(
    name    => 'スライム',
    hp      => 15,  # ここを変えるだけ!
    attack  => 3,
    defense => 2,
);

# clone()で作られるスライムはすべてHP:15になる
my @slimes = map { $base_slime->clone } 1..10;

前回のコードでは10箇所の修正が必要でしたが、今は1箇所で済みます。これが「ベースをコピーする」アプローチの強みです。

MooX::Cloneの仕組み

MooX::Cloneは、Mooクラスにcloneメソッドを自動的に追加します。内部的には、元のオブジェクトの属性値を取り出して、新しいオブジェクトをnewで作っています。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
# MooX::Cloneがやっていることのイメージ
sub clone ($self) {
    return Monster->new(
        name    => $self->name,
        hp      => $self->hp,
        attack  => $self->attack,
        defense => $self->defense,
        color   => $self->color,
    );
}

しかし、これを自分で書く必要はありません。use MooX::Clone;と書くだけで、この処理が自動的に行われます。

今回の完成コード

今回の最終的なコードです。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
#!/usr/bin/env perl
# 言語: perl
# バージョン: 5.36以上
# 依存: Moo, MooX::Clone(cpanmでインストール)
#
# clone()を使って10体のスライムを量産

use v5.36;

package Monster {
    use Moo;
    use MooX::Clone;

    has name    => (is => 'ro', required => 1);
    has hp      => (is => 'rw', required => 1);
    has attack  => (is => 'rw', required => 1);
    has defense => (is => 'rw', required => 1);
    has color   => (is => 'rw', default => '緑');

    sub show_status ($self) {
        say "【" . $self->name . "】HP:" . $self->hp
            . " 攻撃:" . $self->attack
            . " 防御:" . $self->defense
            . " 色:" . $self->color;
    }
}

# ベーススライムを1体作成
my $base_slime = Monster->new(
    name    => 'スライム',
    hp      => 10,
    attack  => 3,
    defense => 2,
);

# clone()で量産(たった1行!)
my @slimes = map { $base_slime->clone } 1..10;

say "=== スライム軍団(10体)===";
for my $slime (@slimes) {
    $slime->show_status;
}

まとめ

  • MooX::Cloneを使うと、Mooクラスにclone()メソッドが追加される
  • clone()は既存オブジェクトをコピーして新しいオブジェクトを作る
  • ベースオブジェクトを1つ作り、clone()で量産することで、コードが劇的に短くなる
  • 修正もベースを変えるだけで済むため、保守性が向上する

次回予告

次回は、clone()で作ったオブジェクトの属性を変更する方法を学びます。赤スライム、青スライム、金スライムなど、色違いモンスターを量産してみましょう。お楽しみに。

comments powered by Disqus
Hugo で構築されています。
テーマ StackJimmy によって設計されています。