#Strategy
目次
目的に書いてあること以外に表現のしようがないんですが、より噛み砕いて言うとアルゴリズムの共通化できる部分を抽象化し振る舞いを具象クラスで実装するような感じです。
##目的
アルゴリズムの集合を定義し、各アルゴリズムをカプセル化して、それらを交換可能にする。Strategy パターンを利用することで、アルゴリズムを、それを利用するクライアントからは独立に変更することができるようになる。
##構成要素
・Strategy 共通部分の抽象クラス
・ConcreateStrategy 共通部分の具象クラス
・Context アルゴリズム部分
##実装
配列をソートするアルゴリズムであるバブルソートとシェーカーソートを実装してみます。
###Strategy 共通部分の抽象クラス
package strategy
interface Sort {
fun swap(index: Int)
fun outOfOrder(index: Int): Boolean
fun length(): Int
fun setArray(array: Any)
}
###ConcreateStrategy 共通部分の具象クラス
Int型の配列用です。
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 アルゴリズム部分
バブルソートから実装します。
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
}
}
次はシェーカーソート
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
}
}
では早速ソートしてみます。
###使う人
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メソッドで設定する配列の型を変えるだけですが...
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>
}
}
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パターンと非常に相性のよさそうなパターンですね。
IntSort
やDoubleSort
クラスをFactory Methodクラスが生成してあげるようにすれば、非常に便利なモジュールが作成できそうです。
以上