【Gang of Four】デザインパターン学習 - Template Method


Template Method - 鋳型

目次
アルゴリズムの共通部分を抽象化して、振る舞いが異なる部分を具象クラスで実装するパターンです。説明だけ読むとStrategyパターンと同じですがあっちは委譲、こっちは継承で実現します。

継承は依存関係が強力になってしまうので個人的にはStrategyパターンのほうが優れているのではないかな?と思っています。

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

目的

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

構成要素

・AbstractClass 共通部分
・ConcreteClass 共通じゃない部分

実装

Strategyパターンと同様、配列をソートするプログラムを実装します。

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

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

以上