集約(has a関係)
自クラスの性質に直接関係のない場合はこちらを使う。
BがAの機能が欲しい場合に「BがAをクラスのメンバとして持つ」という考え方です。
Bのメソッドの中でAの処理を行うので外部(クライアント側)に知識が漏れません。
実装方法
コンストラクタで別クラスを受けてプライベート変数(_を先頭につけた変数)などに外部クラスを代入します。
デメリット
「一部分の処理だけが欲しい」のか、「全ての処理が欲しい」のかがわからなくなってしまう点です。
集約を使う上でのガイドライン
実際に使っているのは一部だが、「別クラスの概念自体」が欲しい場合は使っても良い
例えば、「ファイルクラス」と「ファイル監視クラス」があった場合に「ファイル監視クラス」ではファイルクラスの一部しかメンバを使わない場合であっても「ファイルという概念自体」を監視しているのでこれはファイルクラス自体をメンバとして持たせてしまっても問題ないケースになります。
逆に、一部のプロパティやメソッドが欲しいだけで概念自体はいらないと言った場合は集約を使うのはNGになります。
継承(is a関係)
意味的な集合としてまとめられる場合はこちらを使う。主に以下のようなデザインパターンでは継承を使うのが良いとされています。
- ポリモーフィズム
- リスナ
- ファクトリ
なお、具象クラスを継承して使うのはNGです。なぜならスーパークラスを読まなければサブクラスを読めないためです。あくまで上記のデザインパターンを使えると思った時のみ具象クラスの継承は使うようにしましょう。(例外としては、C#のWindowsFormだったり、JavaのStrutsのアクションクラスだったりとかフレームワークで用意されているクラスを継承する場合を除く)
注意点:「似てるもの」には使わないこと
例えば、製品Aと似ている製品Bがあると思いますが、そういう似ている関係では継承は使わない方が良いです。(似ているものはあくまで別物であり別の拡張を遂げていく可能性があり可読性が下がるため)あくまで「雑種は犬です」のようなis a関係が成り立つ場合のみに継承は使うようにしましょう。
集約と継承がどちらも使えてしまうケース
例えば、ゲームを作っていて「キャラクタークラス」と「衝突を扱う物理オブジェクトクラス」というものがあったとして、キャラクターは衝突を扱う物理オブジェクトである(is a)でも成り立ちますし、「キャラクターが物理オブジェクトを持っている」という関係でも成り立ちます。
この場合は以下二つの面を考えると集約の方が良いと言われます。
柔軟性
可読性
一つの継承元から継承先がどんどん増えていくと継承元のコードは継承先のコードのことも考えて保守をする必要が発生してしまう。
委譲
継承と異なり、子が親と同じ責務を果たすのではなく子が親をツールとして使用する場合に使います。
この記事へのコメントはありません。