@nqounetです。
「Mooで覚えるオブジェクト指向プログラミング」シリーズの第6回です。
前回の振り返り
前回は、requiredで必須パラメータを強制し、defaultで安全なデフォルト値を設定する方法を学びました。
like_count属性を追加して、いいね機能を実装しましたね。
今回は、 内部実装を外から触らせない方法 を学びます。オブジェクト指向の重要な概念、 カプセル化 の入門編です。
内部状態を直接いじられる問題
前回のコードでは、like_countをis => 'rw'で定義しました。これは便利ですが、実は危険な落とし穴があります。
| |
いいね数がマイナスになってしまいました。現実世界では、いいね数がマイナスになることはありませんよね。
is => 'rw'だと、外部から自由に値を設定できてしまいます。小さなプログラムなら「変な値を入れないように気をつければいい」で済みますが、大きなプログラムではそうはいきません。
「誰がこんな値を設定したんだ?」と追跡するのは大変です。そもそも、 不正な値を設定できないようにする のが正しい設計です。
解決策:アンダースコアで内部属性を示す
Perlでは慣習として、 アンダースコア(_)で始まる属性やメソッドは「内部用」 という意味を持ちます。これは「直接触らないでね」というサインです。
| |
like_countを_like_countに変更しました。アンダースコアで始まる属性名は、「このクラスの内部でのみ使う属性ですよ」という宣言になります。
ただし、これは 約束事 であり、Perlが強制するものではありません。$msg->_like_count(100)と書けば、外部からでも呼び出せてしまいます。しかし、アンダースコアで始まる名前を見れば、多くのPerlプログラマは「これは触ってはいけないものだ」と理解します。
解決策:公開メソッド経由で安全に操作
内部属性を隠したら、次は 安全に操作できる公開メソッド を用意します。このメソッド内でバリデーション(検証)を行うことで、不正な値を防ぎます。
| |
このコードのポイントは以下の通りです。
_like_countはis => 'ro'に変更し、外部からの書き込みを禁止add_likeメソッドでのみ、いいね数を増やせるlike_countメソッドで、現在のいいね数を読み取れる
これで、いいね数を 増やすことはできるが、減らしたり任意の値に設定したりはできない という設計になりました。
「いいねを取り消す機能が必要なら?」という場合は、remove_likeメソッドを追加して、その中で「0未満にはしない」というロジックを書けばいいのです。ルールを一箇所に集約できるので、バグを防ぎやすくなります。
まとめ
_で始まる属性名は「内部用」という慣習(Perlが強制するわけではない)- 内部属性は
is => 'ro'にして、外部からの直接変更を禁止する - 公開メソッド経由でのみ操作することで、不正な値を防げる
- この設計パターンを カプセル化 と呼ぶ
次回予告
次回は、掲示板に新しいクラスを追加します。メッセージを投稿する「ユーザー」を表すUserクラスを作り、複数のクラスが連携する設計を学びます。お楽しみに。
