🔨

デザインパターン:Simple Factoryパターン

2024/04/03に公開

これは何?

オブジェクトの生成の際、細かい部品の生成ロジックをカプセル化していい感じに生成してくれるマン

何が嬉しいのか

問題

車を作りたいとして、コンストラクタに材料を渡さないといけない

/** 車 */
class Car {
    constructor(
        readonly handle: Handle,
        readonly tires: Tire[],
        readonly doors: Door[],
        ....
    ){}
}

/** タイヤ */
class Tire {
    constructor(
        readonly wheel: Wheel,
        readonly rubber: Rubber,
        ....
}

/** タイヤのホイール */
class Wheel {
    constructor(readonly steel: Steel, ...){}
}
/** 鋼鉄 */
class Steel {
    constructor(readonly iron: Iron, ...){}
}

これをどこかでconstructしようとすると、細かい材料までその場で生成しないといけない

// client
const leftFrontTire = new Tire(new Wheel(new Steel(...),...), new Rubber())
const rightFrontTire = ...
const leftRearTire = ...
const rightRearTire = ...

const car = new Car(
    [
        leftFrontTire,
        rightFrontTire,
        leftRearTire,
        rightRearTire,
    ],
    new Handle(
        ...
    ),
    [
        new Door(....
	...
)

車をほしい人がタイヤのホイールの材料である鋼鉄の精製まで自分でやらなきゃいけないのはいかがなものか?

解決

車工場を作って全部をぶん投げる

class CarFactory {
    create(): Car {
        return new Car(
            ..... // めっちゃ長い
        )
    }
}

呼ぶ側はfactoryの create メソッドを呼ぶだけ

// client
const carFactory = new CarFactory()

const car = carFactory.create()

その他推しポイント

子の生成もカプセル化していける

車工場がタイヤのホイールの材料である鋼鉄の精製まで自分でやらなきゃいけないのはいかがなものか?という問題もあるので再帰的にfactoryを作る

/**
* タイヤ工場
* ホイールやゴムの作り方はホイール工場やゴム工場に任せているので何も知らない
*/
class TireFactory {
    create(): Tire {
        const wheelFactory = new WheelFactory()
        const rubberFactory = new RubberFactory()

        const wheel = wheelFactory.create()
        const rubber = rubberFactory.create()

        return new Tire(wheel, rubber)
    }
}

/**
* ホイール工場
* 鋼鉄の作り方は鋼鉄工場に任せているので何も知らない
*/
class WheelFactory { ...

条件分岐も隠蔽できる

複雑な条件分岐も書けるけどマッチョになりすぎるので注意(↑と併用するとfactoryを使い回せてちょっと便利)

class CarFactory {
    create(type: CarType): Car {
        switch(type) {
            case("Prius"):
                return new Car(...)
            case("Carolla"):
                ....
        }
    }
}

Static Methodでシンプルに書ける

class Car {
    static create() {
        ...
    }
}

// client
const car = Car.create()
class CarFactory {
    tireFactory: TireFactory
    create() {
        const tire = this.tireFactory.create()
        ...
    }
}

動く実装例

https://www.typescriptlang.org/play?#code/PTAEGUEsFsAcBsCmoBiBDAxgFwPYCcBPAKCOACozRApuNDOCI3jQGdnQBhNPUAbyNFBIAZlhR4cAOywAVSHkQAuULPn9QeSAHMAFqPFSVi5XMRrhWAEqIuhpYbUadl63lvHVAjJOZY8AV2x8AAosE2Y7EwBtAF0ASl41ASxtSGYAOnMxSRkTUABeUFD5ZkiABmjEwpT0x10sg1yCosQSgEYKgSTqjMQRKxtGwrDIgCYOzuTUtNrnAfl8oeLIgGZxgF8iDdIKUEB+hkAShkAThlp6RhY2QwSBZkgALyMJP2gAI0Q8NS8JH39AvCCb+5KR4vN6xPidKpTAHIArQtQbLZnVgcLjoX4EK6gciUQDkmoBZBkAIgxUQAWDIB4HUAqgxEwBJDIAdeUAMQyAaIYTh95GgsIh-ncjAAiJh4TSIbmgAA+oG5zGgaHg8G5sSUnG44M6zAA7pAsBhtJz7mDKp4WBzeVwBbKFHrOvIsH48BJQBJECqUX9IuaIfbHYYgq1SrEADSuzru9wc71+gMCIOe1ojP1YsCAGP1AFTxgDsGQCdpoAZBkAhgyAcIZAMYMxMA5gyAaQYCeG7Q7g16Y-6IRC4uaMAaguLJdLTQHLdbbUGFUEXbXa5GTEEAKxhgduiuesc1icRqfDgBs47n5Y9S5XA-rEI2AgRJE+PlAjbwaNwhAWPdRmHPBCCsQP3iwgmNiAVCxPZ-wBDSGFZ7ObPkTQfQ8cCQDIcE0IIgLfLgehEeocnkNJoXiEBQG9R8vmfCUpXgd8Ck-G9v1-f9DVwtsQO8MDEAgqCKPwuCZn6VwTBQrk0LARcgA

Discussion