여러 방식의 정렬을 구현하는 클래스를 만들어 사용할 때 전략 패턴을 사용하지 않는다면 아래와 같이 작성할 수 있다.
이 방법은 간단하지만, 확장성의 부재가 있다. 새로운 정렬 알고리즘을 추가할 때마다 Sorter
클래스를 수정해야 하므로 OCP를 위반한다.
class Sorter {
fun sortArray(arr: Array<Int>, algorithmType: String): Array<Int> {
return when (algorithmType) {
"bubble" -> bubbleSort(arr)
"quick" -> quickSort(arr)
// 추가 정렬 알고리즘이 필요할 경우 여기에 코드 추가
else -> arr
}
}
private fun bubbleSort(arr: Array<Int>): Array<Int> {
// 버블 정렬 로직 구현
// ...
return arr
}
private fun quickSort(arr: Array<Int>): Array<Int> {
// 퀵 정렬 로직 구현
// ...
return arr
}
// 추가 정렬 알고리즘이 필요할 경우 여기에 메서드 추가
}
전략 패턴 디자인은 정렬 방법을 정의하고 각각을 캡슐화하여 이들을 교환 가능하게 만든다. 해당 알고리즘을 사용하는 클라이언트로부터 독립적으로 변화할 수 있게 해준다.
우선 인터페이스를 만들고 모든 정렬 알고리즘이 구현할 sort
메서드를 선언한다.
interface SortingStrategy {
fun sort(arr: Array<Int>): Array<Int>
}
버블 정렬과 퀵 정렬 알고리즘을 위한 구체적인 전략을 구현한다. 각 전략은 자체적으로 정렬 로직을 캡슐화하여 관심사를 분리한다.
class BubbleSortStrategy : SortingStrategy {
override fun sort(arr: Array<Int>): Array<Int> {
// 버블 정렬 알고리즘 구현
// ...
return arr
}
}
class QuickSortStrategy : SortingStrategy {
override fun sort(arr: Array<Int>): Array<Int> {
// 퀵 정렬 알고리즘 구현
// ...
return arr
}
}
마지막으로 클라이언트에서는 기존 코드 구조를 변경하지 않고도 동적으로 정렬 전략을 선택할 수 있게 된다.
fun main() {
val array = arrayOf(3, 1, 4, 1, 5, 9, 2, 6, 5, 3, 5)
var sorter: SortingStrategy = BubbleSortStrategy()
sorter.sort(array)
sorter = QuickSortStrategy()
sorter.sort(array)
}
전락 패턴을 도입하면서 다양한 알고리즘을 쉽게 전환하거나 새로운 알고리즘을 도입할 때 기존 코드를 수정할 필요가 없어졌고 알고리즘을 그 자체 클래스로 캡슐화함으로써 코드 베이스가 관리하기 쉬워지고 오류 가능성을 줄일 수 있다.