⛳
多様性を意識したデザインパターン
動物の分類
動物について、オブジェクト指向で表現しようと思う。
動物の種類といっても、いろいろいる。猫や犬、鳥など、今回はここら辺を例として挙げよう。
テンプレートメソッドPatternでの記述
これをテンプレートメソッドpatternで書き表すと、
- おおもとの分類クラス
abstract class AnimalTemplate {
// テンプレートメソッド(処理の流れを定義)
public function describe(): void {
echo "生物分類: " . $this->classifyBiology() . "\n";
echo "生態分類: " . $this->classifyEcosystem() . "\n";
echo "----------------------------\n";
}
// サブクラスが実装する抽象メソッド
abstract protected function classifyBiology(): string;
abstract protected function classifyEcosystem(): string;
}
- 具象クラス
class CatAnimal extends AnimalTemplate {
protected function classifyBiology(): string {
return "哺乳類 > 食肉目 > ネコ科";
}
protected function classifyEcosystem(): string {
return "小型捕食者・単独行動・ペット";
}
}
class DogAnimal extends AnimalTemplate {
protected function classifyBiology(): string {
return "哺乳類 > 食肉目 > イヌ科";
}
protected function classifyEcosystem(): string {
return "中型捕食者・群れ行動・番犬・ペット";
}
}
class BirdAnimal extends AnimalTemplate {
protected function classifyBiology(): string {
return "鳥類 > スズメ目 > ○○科";
}
protected function classifyEcosystem(): string {
return "飛翔性・雑食性・観賞用ペット";
}
}
$animals = [
new CatAnimal(),
new DogAnimal(),
new BirdAnimal()
];
foreach ($animals as $animal) {
$animal->describe(); // ← テンプレートメソッドが呼ばれる!
}
メリットとデメリット
実際、今までの感じたとこれが普通のように思える。処理の流れが共通化されており、わかりやすい。
ただ、これだとデメリットが存在する。
組み合わせに限界が来るのである。
というのも、変わった生物(ネコ生物+イヌ生態など)がいると、途端に破綻するのである。
その変わった生物専用のクラスを作らなくてはいけない。
ブリッジPatternでの記述
ここで解決方法がある。
classifyBiology
classifyEcosystem
この二つの分類結果で、種類を判別するのである。
interface petKindsInterface
{
public function classifyBiology(): string;
public function classifyEcosystem(): string;
}
- おおもとの分類クラス
class Animal implements petKindsInterface {
private BiologyClassifier $biology;
private EcosystemClassifier $ecosystem;
public function __construct(BiologyClassifier $biology, EcosystemClassifier $ecosystem) {
$this->biology = $biology;
$this->ecosystem = $ecosystem;
}
public function classifyBiology(): string {
return $this->biology->getClassification();
}
public function classifyEcosystem(): string {
return $this->ecosystem->getClassification();
}
}
- 具象クラス
class DogBiology implements BiologyClassifier {
public function getClassification(): string {
return "哺乳類 > 食肉目 > イヌ科";
}
}
class DogEcosystem implements EcosystemClassifier {
public function getClassification(): string {
return "中型捕食者・番犬・ペット";
}
}
class CatBiology implements BiologyClassifier {
public function getClassification(): string {
return "哺乳類 > 食肉目 > ネコ科";
}
}
class CatEcosystem implements EcosystemClassifier {
public function getClassification(): string {
return "小型捕食者・単独行動・ペット";
}
}
class BirdBiology implements BiologyClassifier {
public function getClassification(): string {
return "鳥類 > スズメ目 > トリ科";
}
}
class BirdEcosystem implements EcosystemClassifier {
public function getClassification(): string {
return "飛翔性・雑食性・観賞用ペット";
}
}
これにより、
$animal = new Animal(new CatBiology(), new DogEcosystem());
このように、分類の組み合わせで無限に動物を表現できるのである。
また、新しい分類の追加が楽で、拡張性が高い。
結果
身もふたもないことを言ったらトレードオフなのである。
- 処理の流れが分かりやすいテンプレートメソッドパターン
- 無限に種類を表現できるブリッジメソッドパターン
うまく使いこなせるようになりたい。
Discussion