Design pattern - Creational patternsを理解する

# はじめに
Creational patternsについて説明します。
Instance化を扱うDesign patternです。

# Dependency inversion principle
**Dependency inversion principle(DIP)**はCreational patternの理解に役立ちます。
そのため、DIPについて説明します。

High-level moduleがLow-level moduleを利用するケースを考えます。

![1.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/84205/83db293d-c7d8-e4f3-f153-46e3c35c3f08.jpeg)

Low-level moduleを変更した場合、High-level moduleに影響を与えます。
High-level moduleとLow-level moduleの依存関係を弱める方策を検討します。

Low-level moduleの**interface**を導入します。
High-level moduleはinterfaceを利用します。Low-level moduleはinterfaceを実装します。
次の図を参照ください。

![1.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/84205/072fed1a-287c-7c33-22bb-1542c78c8acd.jpeg)

interfaceにより依存関係が弱まります。

DIPは次のように表現されます。

>
High-level modules should not depend on low-level modules. Both should depend on abstractions (e.g., interfaces).
Abstractions should not depend on details. Details (concrete implementations) should depend on abstractions.
>


- High-level moduleはLow-level moduleに依存するのではなく、ともにInterface(*1)に依存すべき。
- 実装はInterface依存すべき。

(\*1) : ここの例ではLow-level moduleのinterface
(\*2) : ここの例ではLow-level moduleの実装

# Instance化
User classがIProduct interfaceを利用するケースを考えます。

![1.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/84205/188259c5-e2fa-66ea-07aa-aae26ef4ea54.jpeg)

IProductはinterfaceであるためinstance化することができません。
そのためIProductを実装します。実装をProductとします。
次の通りです。

![1.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/84205/42131375-c820-28f5-f73b-51140c2ca964.jpeg)

UserはProductをどのようにinstance化すればいいのでしょうか。
UserはIProductのみに依存し、Productには依存したくありません。

Creational patternsはこの課題に対処する方法を与えます。

# Factory Method
Productのinstance化をUserのsubclassに任せる方法を**FactoryMethod**といいます。

![1.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/84205/34b0dcc6-13e1-4f59-d6d1-ed424456720a.jpeg)

実装例を示します。
makeProductをFactoryMethodといいます。

```kotlin:test.kt
interface IProduct {
    fun method()
}

class Product : IProduct {
    override fun method() {
        println("Product:method")
    }
}

abstract class User {
    protected abstract fun makeProduct(): IProduct

    fun method() {
        val product = makeProduct()
        println("call IProduct:method")
        product.method()
    }
}

class UserImpl : User() {
    override fun makeProduct(): IProduct {
        return Product()
    }
}

fun callMethod(user: User) {
    println("call User:method")
    user.method()
}

fun main() {
    val user = UserImpl()
    callMethod(user)
    /*
        call User:method
        call IProduct:method
        Product:method
     */
}
```

# Factory Object / Abstract Factory
Productのinstance化をObjectに委譲します。
ここでは便宜的に**FactoryObject**といいます。

![1.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/84205/6bbeabd2-5134-a312-4885-337e2116252c.jpeg)

複数Productのinstance化をFactory objectに委譲します。
Userは直接Factoryには依存したくないため、IFactory interfaceを導入します。
次の通りです。

![1.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/84205/1fa28b67-5c48-e1b6-52b2-482a64a9eb69.jpeg)

Productの実装を切り替えたい場合は次のようにして対処します。
**AbstractFactory**といいます。

![1.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/84205/41a20138-2859-9fb4-5843-809b5ca6ddd8.jpeg)

実装例を示します。

```kotlin:test.kt
interface IProductA {
    fun method()
}

class Product1A : IProductA {
    override fun method() {
        println("Product1A:method")
    }
}

class Product2A : IProductA {
    override fun method() {
        println("Product2A:method")
    }
}

interface IProductB {
    fun method()
}

class Product1B : IProductB {
    override fun method() {
        println("Product1B:method")
    }
}

class Product2B : IProductB {
    override fun method() {
        println("Product2B:method")
    }
}

interface IFactory {
    fun makeProductA(): IProductA
    fun makeProductB(): IProductB
}

class Factory1 : IFactory {
    override fun makeProductA(): IProductA {
        return Product1A()
    }

    override fun makeProductB(): IProductB {
        return Product1B()
    }
}

class Factory2 : IFactory {
    override fun makeProductA(): IProductA {
        return Product2A()
    }

    override fun makeProductB(): IProductB {
        return Product2B()
    }
}

class User(private val factory: IFactory) {
    fun method() {
        val productA = factory.makeProductA()
        val productB = factory.makeProductB()
        println("Call IProductA:method")
        productA.method()
        println("Call IProductB:method")
        productB.method()
    }
}

fun main() {
    User(Factory1()).method()
    User(Factory2()).method()
    /*
        Call IProductA:method
        Product1A:method
        Call IProductB:method
        Product1B:method
        Call IProductA:method
        Product2A:method
        Call IProductB:method
        Product2B:method
     */
}
```

# Builder
複数objectの合成によって生成されるobjectを**complex object**といいます。
複数objectを生成して、組み立て(assemble)ることでcomplex objectをinstance化します。
次の図を参照ください。

![1.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/84205/13b8f17c-fcec-854d-e9de-8fd6757e48ac.jpeg)

ProductはPartA / PartBをもちます。
BuilderはPartA / PartB / Productをinstance化します。
DirectorはBuilderをつかってProductを組み立てます。
UserはDirectorからProductのinstanceを取得します。

実装例を示します。

```kotlin:test.kt
interface IProduct {
    fun method()
}

class Product(private val partA: PartA, private val partB: PartB) : IProduct {
    override fun method() {
        println("call PartA:method")
        partA.method()
        println("call PartB:method")
        partB.method()
    }
}

class PartA {
    fun method() {
        println("PartA:method")
    }
}

class PartB {
    fun method() {
        println("PartB:method")
    }
}

interface IBuilder {
    fun makePartA(): PartA
    fun makePartB(): PartB
    fun makeProduct(partA: PartA, partB: PartB): IProduct
}

class Builder() : IBuilder {
    override fun makePartA(): PartA {
        return PartA()
    }

    override fun makePartB(): PartB {
        return PartB()
    }

    override fun makeProduct(partA: PartA, partB: PartB): IProduct {
        return Product(partA, partB)
    }
}

interface IDirector {
    fun makeProduct(): IProduct
}

class Director(private val builder: IBuilder) : IDirector {
    override fun makeProduct(): IProduct {
        val partA = builder.makePartA()
        val partB = builder.makePartB()
        return builder.makeProduct(partA, partB)
    }
}

class User() {
    fun method() {
        val builder = Builder()
        val director = Director(builder)
        val product: IProduct = director.makeProduct()
        println("call IProduct:method")
        product.method()
    }
}

fun main() {
    User().method()
    /*
        call IProduct:method
        call PartA:method
        PartA:method
        call PartB:method
        PartB:method
     */
}
```

# Injection
User / IProductの外部にあるInjectorがProductをinstance化します。
InjectorはProductをUserに渡します。渡すことをinjectionといいます。

![1.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/84205/dca0f5cc-1bd2-ac4e-8582-6804ca7fef66.jpeg)

実装例を示します。

```kotlin:test.kt
interface IProduct {
    fun method()
}

class Product : IProduct {
    override fun method() {
        println("Product:method")
    }
}

class User(private val product: IProduct) {
    fun method() {
        println("call IProduct:method")
        product.method()
    }
}

class Injector {
    fun method() {
        User(Product()).method()
    }
}

fun main() {
    Injector().method()
    /*
        call IProduct:method
        Product:method
     */
}
```

# References
- [1] https://en.wikipedia.org/wiki/Software_design_pattern
- [2] https://en.wikipedia.org/wiki/Dependency_inversion_principle