DevCho
Developer Blog
DevCho
반응형
전체 방문자
오늘
어제
  • 분류 전체보기 (48)
    • IOS (31)
      • Xcode (7)
      • Assets (1)
      • Swift (20)
      • UI (1)
      • SwiftUI (1)
      • Build (1)
    • Flutter (4)
      • Install (4)
      • Dart (0)
    • Rust (0)
    • 유용한 사이트 소개 (1)
    • 개발자의 아이템 (1)
    • Terminal (1)
    • Mac (2)
    • Git (1)
    • 회고 (1)
    • Java (2)
      • Java 기본 사용법 (2)
      • Collections (0)
    • 개발자의 글쓰기 (0)
    • 디자인 패턴 (1)
    • JavaScript (2)
    • Kotlin (1)

블로그 메뉴

  • 홈
  • 태그
  • 방명록

공지사항

인기 글

태그

  • dart 설치
  • flutter
  • MAC
  • Terminal
  • 플러터 설치
  • dart
  • flutter install
  • Dark mode
  • func
  • chocolatey
  • random number
  • optional
  • swift random
  • Storyboard
  • Xcode Theme
  • 제어문
  • chocolatey 설치
  • 스위프트
  • chocolatey install
  • CLASS
  • IOS
  • flutter dart
  • xcode
  • Java
  • Swift
  • SwiftUI
  • xcode13
  • flutter 설치
  • nil
  • struct

최근 댓글

최근 글

티스토리

hELLO · Designed By 정상우.
DevCho

Developer Blog

디자인 패턴

[Kotlin Design Pattern] Command Pattern 구현해보기

2022. 7. 11. 21:00
반응형

커맨드 패턴

커멘드 패턴이란 한 객체의 다른 객체에 대한 요청(Command)를 커멘드 객체로 캡슐화 해서 커멘드 객체에서 하는 일을 신경쓰지 않고 메서드를 수행하도록 하는 패턴이다.

 

커멘드 패턴은 복잡한 패턴이라서 말로만 들으면 어떤 내용인지 이해하기가 어렵다. 아래에서 직접 커멘드 패턴을 사용하지 않고 여러 객체를 조작하는 방법과 커멘드 패턴을 사용해서 여러 객체를 조작하는 방법에 대해 살펴보자.

 

커멘드 패턴을 사용하지 않고 여러 객체 조작하기

만약 커멘드 패턴을 사용하지 않고 하나의 객체가 여러 객체를 조작하기 위해서는 여러 객체 각각에 대한 처리를 해야한다. 예를 들어 리모컨이 여러 전등(Light)를 크고 끌 수 있도록 설계되어야 하는 상황을 생각해보자. 각 전등은 다른 제조사에서 개발되어서 구현체가 달라 메서드를 공통으로 사용하지 않는다. 그러면 다음과 같이 구현해야 한다.

 

class LightController() {
    fun setMainLightOn(mainLight : MainLight) {
        mainLight.on()
    }
   
    fun setSubLightOn(subLight: SubLight) {
        subLight.turnOn()
    }
   
    fun setBedRoomLightOn(bedRoomLight: BedRoomLight) {
        bedRoomLight.light()
    }
}

 

위 메서드들을 수행하려면 다음과 같이 수행해야 한다.

fun main() {
    val lightController = LightController()
    val mainLight = MainLight()
    val subLight = SubLight()
    lightController.setMainLightOn(mainLight)
    lightController.setSubLightOn(subLight)
}

 

위 방식은 새로운 전등(Light)이 생길 때마다 수록 각 전등에 대한 메서드를 LightController에 정의해야 된다. 또한 모든 메서드들이 특정 구현체에 의존하고 있기 때문에 LightController가 전등(Light)을 조작하기 위해 직접 전등의 메서드를 조작해야 한다.

 

 

커멘드 패턴 사용해 여러 객체 조작하기

 위와 같은 문제를 해결하기 위해서, 커멘드 패턴은 요청을 객체로 캡슐화해서 같은 메서드로 요청을 수행할 수 있도록 한다. 즉, 인터페이스를 구현하는 방식으로 커멘드(요청)를 커멘드 객체로 캡슐화 해서 커멘드 객체에서 하는 일을 신경쓰지 않고 메서드를 수행하도록 하는 패턴이다.

커멘드 패턴에서는 요청을 위한 인터페이스를 만들어서 이를 구현하는 방식으로 명령을 처리한다.

 

 

interface Command {
    fun execute()
}

 

class MainLightOnCommand(private val mainLight: MainLight) : Command {
    override fun execute() {
        mainLight.on()
    }
}


class SubLightOnCommand(private val subLight: SubLight) : Command {
    override fun execute() {
        subLight.turnOn()
    }
}


class BedRoomLightOnCommand(private val bedRoomLight: BedRoomLight) : Command {
    override fun execute() {
        bedRoomLight.light()
    }
}

 

그러면 LightController는 다음과 같이 바뀌게 된다.

class LightController() {
    fun executeCommand(command: Command) {
        command.execute()
    }
}

 

LightController는 더이상 다양한 Light를 조작하는 메서드를 일일히 만들지 않아도 되며, 다음과 같이 사용하면 된다.

 

fun main() {
    val lightController = LightController()
    val mainLight = MainLight()
    val subLight = SubLight()
    lightController.doCommand(MainLightOnCommand(mainLight))
    lightController.doCommand(SubLightOnCommand(subLight))
}

 

 

 

커멘드 패턴 예제

위와 같이 서로 다른 회사가 만든 문서 편집 기능들을 모아놓은 ATypeDocumentCommand와 BTypeDocumentCommand가 있다고 해보자.

class ATypeDocumentCommand() {
   fun add() {
        // 페이지 추가
    }

   fun delete() {
        // 페이지 삭제
    }
}

class BTypeDocumentCommand() {
   fun copyPage() {
        // 페이지 복사
    }

   fun pastePage() {
        // 페이지 붙여넣기
    }
}

 

각 DocumentCommand는 다른 회사에서 만들어서 동일 인터페이스를 구현하지 않는다. 이 경우에 우리는 키보드에서 단축키를 사용해 각 DocumentCommand를 사용하고 싶다 DocumentCommand들을 단축키로 사용할 수 있도록 KeyBoardController를 만들어보자.

 

이 객체들에 사용할 Command를 다음과 같이 정의한다.

interface Command {
    fun execute()
}

class DocumentAddCommand(private val document: ATypeDocument) : Command {
    override fun execute() {
        document.add()
    }
}

class DocumentCopyCommand(private val document: BTypeDocument) : Command {
    override fun execute() {
        document.copyPage()
    }
}

 

이제 키보드 단축키를 사용해서 위 명령들을 수행할 수 있도록 해보자. 단축키를 설정하기 위해 setCommand로 key(단축키)와 명령 command를 받아 map에 넣고 해당 단축키를 눌렀을 때 pressButton 메서드가 수행되어 단축키에 저장된 command가 수행된다. 

class KeyBoardController() {
    var map: MutableMap<String, Command> = mutableMapOf()

    fun setCommand(key: String, command: Command) {
        map[key] = command
    }

    fun pressButton(key: String) {
        map[key]?.execute()
    }
}
반응형
    DevCho
    DevCho
    개발자의 개발 공간

    티스토리툴바