【Gang of Four】Strategy

#Strategy
**[目次](https://qiita.com/Tonkachi0620/items/03986742efbb7e3a9bbe)**
目的に書いてあること以外に表現のしようがないんですが、より噛み砕いて言うとアルゴリズムの共通化できる部分を抽象化し振る舞いを具象クラスで実装するような感じです。

##目的
アルゴリズムの集合を定義し、各アルゴリズムをカプセル化して、それらを交換可能にする。Strategy パターンを利用することで、アルゴリズムを、それを利用するクライアントからは独立に変更することができるようになる。 

##構成要素
・Strategy 共通部分の抽象クラス
・ConcreateStrategy 共通部分の具象クラス
・Context アルゴリズム部分

##実装
配列をソートするアルゴリズムであるバブルソートとシェーカーソートを実装してみます。

###Strategy 共通部分の抽象クラス

```Sort.kt
package strategy

interface Sort {
    fun swap(index: Int)
    fun outOfOrder(index: Int): Boolean
    fun length(): Int
    fun setArray(array: Any)
}
```

###ConcreateStrategy 共通部分の具象クラス
Int型の配列用です。

```IntSort.kt
package strategy

class IntSort: Sort {
    private lateinit var array: Array<Int>

    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]
    }

    override fun length(): Int {
        return array.size
    }

    override fun setArray(array: Any) {
        this.array = array as Array<Int>
    }
}
```

###Context アルゴリズム部分
バブルソートから実装します。

```BubbleSort.kt
package strategy

class BubbleSort(private val sort: Sort) {
    private var operations = 0
    private var length = 0

    fun sort(array: Any): Int {
        sort.setArray(array)
        length = sort.length()
        operations = 0

        if (length <= 1) {
            return operations
        }

        for (nextToLast in length - 2 downTo 0) {
            for (index in 0..nextToLast) {
                if (sort.outOfOrder(index)) {
                    sort.swap(index)
                }
                operations++
            }
        }

        return operations
    }
}
```

次はシェーカーソート

```ShakerSort.kt
package strategy

class ShakerSort(private val sort: Sort) {

    fun sort(array: Any): Int {
        sort.setArray(array)
        var length = sort.length()
        var operations = 0

        if (length <= 1) {
            return operations
        }

        var thisPassInOrder = false

        loop@ for (nextToLast in length - 2 downTo 0) {
            if (thisPassInOrder) {
                break@loop
            }

            thisPassInOrder = true
            for (index in 0..nextToLast) {
                if (sort.outOfOrder(index)) {
                    sort.swap(index)
                    thisPassInOrder = false
                }
                operations++
            }
        }
        return operations
    }
}
```

では早速ソートしてみます。
###使う人

```Client.kt
package strategy

class Client {
    init {
        val array1 = arrayOf(22,533,43212,1,567,7,22,2,35,9913)
        val array2 = arrayOf(25,77,834534,32,11,3,880)

        val intSort = IntSort()

        // バブルソート
        BubbleSort(intSort).sort(array1)

        println("バブルソート結果")
        array1.forEach {
            println("$it")
        }

        // シェーカーソート
        ShakerSort(intSort).sort(array2)

        println("シェーカーソート結果")
        array2.forEach {
            println("$it")
        }
    }
}
```

```
[out-put]
バブルソート結果
1
2
7
22
22
35
533
567
9913
43212
シェーカーソート結果
3
11
25
32
77
880
834534
```

DIPに則ったコードにより柔軟な実装が可能になっているパターンです。

Int型の配列だけでなく、例えば```Sortインタフェース```を実装した```DoubleSort```を作ります。
setArrayメソッドで設定する配列の型を変えるだけですが...

```DoubleSort.kt
package strategy

class DoubleSort: Sort {
    private lateinit var array: Array<Double>

    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]
    }

    override fun length(): Int {
        return array.size
    }

    override fun setArray(array: Any) {
        this.array = array as Array<Double>
    }
}
```


```Client.kt
package strategy

class Client {
    init {
        val array1 = arrayOf(33.5, 5.4, 5.0, 225.4, 225.3)
        val array2 = arrayOf(10.4, 10.2, 10.5, 10.1, 10.3, 10.6)

        val doubleSort = DoubleSort()

        // バブルソート
        BubbleSort(doubleSort).sort(array1)

        println("バブルソート結果")
        array1.forEach {
            println("$it")
        }

        // シェーカーソート
        ShakerSort(doubleSort).sort(array2)

        println("シェーカーソート結果")
        array2.forEach {
            println("$it")
        }
    }
}
```

###出力結果
```
[out-put]
バブルソート結果
5.0
5.4
33.5
225.3
225.4
シェーカーソート結果
10.1
10.2
10.3
10.4
10.5
10.6
```

[Factory Method](https://qiita.com/Tonkachi0620/items/52e94b05694566a397f1)パターンと非常に相性のよさそうなパターンですね。
```IntSort```や```DoubleSort```クラスをFactory Methodクラスが生成してあげるようにすれば、非常に便利なモジュールが作成できそうです。

以上