👌
最も重要な、Abstract Factoryデザインパターン
こんにちは。今回は、オブジェクト指向において最も重要な、
Abstract Factoryパターンについて、記載します。
一言でいうと?
使用者が抽象だけを扱える形にすることである。
具体例
abstract class Pet { }
class Cat extends Pet { }
class Dog extends Pet { }
class PetBuyer
{
fanction buy(Pet $pet)
{
$pet = match($type) {
'cat' => new Cat(),
'dog' => nre Dog(),
default => throw new InvalidArgumentException()
};
buy($pet}
}
}
これだと、buyがpetの生成の責任を持つことになってしまう。
これはよくないので、分けてあげよう。
abstract class Pet { }
class Cat extends Pet { }
class Dog extends Pet { }
class PetShop
{
public function createPet(string $type): Pet
{
return match($type) {
'cat' => new Cat(),
'dog' => nre Dog(),
default => throw new InvalidArgumentException()
};
}
}
class PetBuyer
{
public function buyPet(PetShop $petShop, string $type)
{
$pet = $petShop->createPet($type);
buy($pet)
}
}
一見、ペットを生成するところが分かれて、buyPetが依存性から脱却されたように思えるが、PetBuyerがcreatePetを名指ししており、Shopに依存している。
つまり、PetShopのpetの種類が変わってしまったら、PetBuyerも影響を受けてしまう。
PetShopは、いろいろなペットを扱うので変更が多くなる可能性があるが、今のままだと、抽象度が低いclassに抽象度が高いclassに依存している形になる。
ファクトリ(データを生成する部分)を切り出す目的は、使用者が抽象を扱えるようにすることである。
どうすべきか
今回は、petBuyがPetShopという具象ファクトリを固定で名指ししている部分が、うまく実装できていないポイントである。ここを依存性逆転原則で突破する。
abstract class Pet { }
interface PetShopInterface
{
public function createPet(string $type): Pet;
}
class PetBuyer
{
public function buyPet(PetShopInterface $petShop, string $type)
{
$pet = $petShop->createPet($type);
buy($pet)
}
}
依存の向きがbuyerに向くshop
class Cat extends Pet { }
class Dog extends Pet { }
class CatAndDogOnlyPetShop implements PetShopInterface
{
public function createPet(string $type): Pet
{
return match($type) {
'cat' => new Cat(),
'dog' => nre Dog(),
default => throw new InvalidArgumentException()
};
}
}
これにより、petShopは抽象度の高いpetShopInterfaceに向き、petBuyerも抽象度の高いpetShopInterfaceに向いていることで、ShopはBuyerの影響を全く気にせず変更できるようになった。
このパターンは、
生成されるオブジェクトを抽象として扱うとき、そのファクトリの扱いも抽象でなければ、原則を守ることができない
と言っているのである。
Discussion