【Gang of Four】Template Method

#Template Method
[目次](https://qiita.com/Tonkachi0620/items/03986742efbb7e3a9bbe)
アルゴリズムの共通部分を抽象化して、振る舞いが異なる部分を具象クラスで実装するパターンです。説明だけ読むと[Strategy](https://qiita.com/Tonkachi0620/items/eba3a647d2828c57f24e)パターンと同じですがあっちは委譲、こっちは継承で実現します。

継承は依存関係が強力になってしまうので個人的には[Strategy](https://qiita.com/Tonkachi0620/items/eba3a647d2828c57f24e)パターンのほうが優れているのではないかな？と思っています。

ただ、こちらのほうが実装するクラスが少なくて済みます。

##目的
1つのオペレーションにアルゴリズムのスケルトンを定義しておき、その中のいくつかのステップについては、サブクラスでの定義に任せることにする。Template Method パターンでは、アルゴリズムの構造を変えずに、アルゴリズム中のあるステップをサブクラスで再定義する。

##構成要素
・AbstractClass 共通部分
・ConcreteClass 共通じゃない部分

##実装
[Strategy](https://qiita.com/Tonkachi0620/items/eba3a647d2828c57f24e)パターンと同様、配列をソートするプログラムを実装します。

###AbstractClass 共通部分
```BubbleSort.kt
package templatemethod

abstract class BubbleSort {
    private var operations = 0
    protected var length = 0

    protected fun doSort(): Int {
        operations = 0
        if (length <= 1) return operations

        for (nextToLast in length - 1 downTo 0) {
            for (index in 0 until nextToLast) {
                if (outOfOrder(index)) swap(index)
                operations++
            }
        }
        return operations
    }

    protected abstract fun swap(index: Int)
    protected abstract fun outOfOrder(index: Int): Boolean
}
```

###ConcreteClass 共通じゃない部分
Int型配列用具象クラス

```IntBubbleSort.kt
package templatemethod

class IntBubbleSort: BubbleSort() {

    private lateinit var array: Array<Int>

    fun sort(theArray: Array<Int>): Int {
        array = theArray
        length = theArray.size
        return doSort()
    }

    override fun swap(index: Int) {
        val temp = array[index]
        array[index] = array[index + 1]
        array[index + 1] = temp
    }

    override fun outOfOrder(index: Int): Boolean {
        return array[index] > array[index + 1]
    }

}
```

Double型配列用具象クラス

```DoubleBubbleSort.kt
package templatemethod

class DoubleBubbleSort: BubbleSort() {

    private lateinit var array: Array<Double>

    fun sort(theArray: Array<Double>): Int {
        array = theArray
        length = theArray.size
        return doSort()
    }

    override fun swap(index: Int) {
        val temp = array[index]
        array[index] = array[index + 1]
        array[index + 1] = temp
    }

    override fun outOfOrder(index: Int): Boolean {
        return array[index] > array[index + 1]
    }
}
```

まあこれもジェネリクス使えば一つのクラスで実現できますが…

###使う人

```Client.kt
package templatemethod

class Client {
    init {
        val intArray = arrayOf(332, 1, 13, 3232, 456, 22, 5)
        println("Int配列ソート前")
        intArray.forEach {
            println(it)
        }
        // 並べ替え
        IntBubbleSort().sort(intArray)
        println("Int配列ソート後")
        intArray.forEach {
            println(it)
        }

        val doubleArray = arrayOf(10.01, 10.5, 10.4123, 10.12, 10.87)
        println("Double配列ソート前")
        doubleArray.forEach {
            println(it)
        }
        // 並べ替え
        DoubleBubbleSort().sort(doubleArray)
        println("Double配列ソート後")
        doubleArray.forEach {
            println(it)
        }
    }
}
```

###出力結果
```
[out-put]
Int配列ソート前
332
1
13
3232
456
22
5
Int配列ソート後
1
5
13
22
332
456
3232
Double配列ソート前
10.01
10.5
10.4123
10.12
10.87
Double配列ソート後
10.01
10.12
10.4123
10.5
10.87
```

かなり基本的なパターンですね。あらゆるところで使用するかと思います。

以上