@nqounetです。
「Perlでローグライク通知システムを作ろう」シリーズの第4回です。前回は、LogObserverとAchievementObserverを独立したクラスとして作成しました。今回は、これらのObserverが共通して持つべき「約束」をMoo::Roleで定義します。
前回の振り返り
前回は、ログと実績を独立したクラスに分離しました。両方のクラスには共通点がありました。
updateという名前のメソッドを持つGameEventを受け取って処理を行う
なぜ「約束」が必要なのか
現在のコードでは、LogObserverもAchievementObserverもupdateメソッドを持っています。しかし、もし新しいObserverを作るとき、updateメソッドを付け忘れたらどうなるでしょうか。
| |
このクラスを作ってしまうと、後で「全てのObserverに通知する」ときにエラーになります。実行時にエラーが出るまで気づけないのは困りますね。
Moo::Role と requires
Moo::Roleのrequiresを使うと、「このRoleを使うクラスは、必ずこのメソッドを実装すること」と宣言できます。
詳しくは「Mooで覚えるオブジェクト指向プログラミング」シリーズの第10回をご覧ください。
GameEventObserverロールを作成する
それでは、「ゲームイベントを受け取るObserver」のルールを定義するRoleを作成しましょう。
| |
実行結果は以下のようになります。
| |
updateメソッドを忘れるとどうなるか
では、updateメソッドを実装せずにRoleを適用したらどうなるでしょうか。
| |
このコードを実行すると、エラーになります。
| |
updateメソッドが実装されていないため、クラスのロード時(=実行時の早い段階)にエラーが発生します。実行時にメソッドを呼び出すまで気づかないよりも、はるかに早く問題を発見できます。
新しいObserverを追加してみよう
Roleの仕組みがあれば、新しいObserverを安心して追加できます。サウンドエフェクト用のObserverを作成してみましょう。
| |
with 'GameEventObserver'を書くことで、「このクラスはGameEventObserverとして機能します」と宣言しています。もしupdateメソッドを忘れたら、すぐにエラーで気づけます。
Roleを使うメリット
Moo::Roleのrequiresを使うことで、以下のメリットがあります。
| メリット | 説明 |
|---|---|
| 契約の明示 | 「Observerは必ずupdateを持つ」という約束が明確 |
| 早期エラー発見 | 実装漏れがあればクラスロード時にエラー |
| ドキュメント効果 | 「このRoleをwithすればObserverになれる」とわかる |
| 拡張の安全性 | 新しいObserverを追加するときの指針になる |
今回のまとめ
今回は、Observerが共通して持つべきメソッドをMoo::Roleのrequiresで定義しました。
GameEventObserverロール:updateメソッドを要求- 各Observerクラス:
with 'GameEventObserver'でRoleを適用 - 実装漏れ防止:
updateを忘れるとクラスロード時にエラー
完成コード
今回の完成コードは以下の通りです。
| |
次回予告
次回は「イベント発生元を管理しよう」です。複数のObserverへの通知を一元管理するGameEventEmitterクラスを作成します。
