-
[패턴] 전략(Strategy) 패턴카테고리 없음 2024. 3. 26. 11:28
TMI
최근에 코드를 짜는데 전략 패턴이 생각나서 전략 패턴을 적용하여 코드를 짜봤다.
아주 간단한 기능이어서 굳이 쓸까 싶었지만 한번 쯤 사용하면 이해되는데 도움이 될거 같아서 사용해봤다.
언제 사용 하는지?
- 같은 결과를 반환하는 동작이지만 내부 코드가 다를 때
- 동작이 런타임 중에 실시간으로 교체되어야 할 때
전략 패턴을 사용하지 않은 예시 코드
enum class Type { ITEMSADDER, MATERIAL } data class Tool( private val id: String ) { // Enum을 이용하여 비교하기 때문에 추후에 타입 추가가 필요하면 Tool 클래스를 수정해야할 것이다. fun isTool(itemStack: ItemStack, type: Type): Boolean { return when (type) { ITEMSADDER -> CustomStack.byItemStack(itemStack)?.id == id MATERIAL -> itemStack.type == Material.matchMaterial(id.uppercase()) } } }
전략 패턴을 사용한 예시 코드
이렇게 원하는 Strategy로 바꿔서 사용할 수 있게 된다.
도구를 비교하는 구문을 ToolStrategy에 위임하여 유지보수가 쉽고
추후 다른 API를 추가하여 비교하고 싶을 때 추가가 쉬운 구조가 되었다.
(Tool 클래스를 전혀 수정하지 않고 상속만 시켜서 만들 수 있게 된다.)(아래는 이전에 만들었던 코드 일부분을 가져왔다.)
interface ToolStrategy { // 둘다 ItemStack과 id로 비교할 수 있기 때문에 ToolStrategy로 인터페이스를 만들었다. fun isTool(itemStack: ItemStack, id: String): Boolean } class ItemsAdderStrategy : ToolStrategy { // 외부 API를 받아 도구인지 체크하는 구문 override fun isTool(itemStack: ItemStack, id: String): Boolean { println("외부 API로 비교") return CustomStack.byItemStack(itemStack)?.id == id } } class MaterialStrategy : ToolStrategy { // 기본 API를 받아 도구인지 체크하는 구문 override fun isTool(itemStack: ItemStack, id: String): Boolean { println("기본 API로 비교") return itemStack.type == Material.matchMaterial(id.uppercase()) } }
data class Tool( private val id: String ) { // 기본 API로 작동하는 MaterialStrategy로 변수 초기화 private var toolStrategy: ToolStrategy = MaterialStrategy() // ToolStrategy를 상속하는 클래스면 모두 비교할 수 있게 된다. fun isTool(itemStack: ItemStack): Boolean { return toolStrategy.isTool(itemStack, id) } // 원하는 ToolStrategy로 변경할 수 있다. fun setToolStrategy(toolStrategy: ToolStrategy) { this.toolStrategy = toolStrategy } }
fun main() { val itemStack = ItemStack(Material.DIAMOND_PICKAXE) val tool = Tool("diamond_pickaxe") if (tool.isTool(itemStack)) { // 출력: 기본 API 비교 // TODO } tool.setToolStrategy(ItemsAdderStrategy()) if (tool.isTool(itemStack)) { // 출력: 외부 API 비교 // TODO } }