👌

最も重要な、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