-
반응형
커맨드 패턴은 메소드 호출을 객체로 캡슐화한다. 커맨드 패턴의 구성요소인 클라이언트(client), 인보커(invoker), 커맨드(command), 리시버(receiver)를 파악하는게 중요하다.
1. UML
아래는 커맨드 패턴의 UML이다.
인보커(Invoker)와 리시버A(ReceiverA), 리시버B(ReceiverB)는 완성된 UML이 아니다. 인보커의 commands를 Map<String, Command>로 사용할 수도 있고, 내부의 함수로 executeAllCommand() 등의 메소드를 만들 수도 있다. 클라이언트(client), 인보커(invoker), 커맨드(command), 리시버(receiver)의 전체적인 구성만 파악하면 된다.
2. 커맨드 패턴 설명
커맨드 패턴에서 각 객체들의 구성은 다음과 같다. 클라이언트는 리시버, 커맨드, 인보커를 모두 구현하고 조합한다. 커맨드의 동작인 리시버를 만들어 커맨드에 주입하고, 리시버가 주입된 커맨드를 인보커에 등록한다. 리시버는 인터페이스가 아닌 커맨드가 실행할 동작의 실제 구현 객체라는 것에 주목해야 하며, 커맨드 구현체는 커맨드 인터페이스의 execute()만을 외부에 노출하고 있다.
커맨드 패턴의 확장 기능으로는 큐(queue)를 사용하여 실행한 명령어를 저장하고 있다가 실행취소(undo)를 구현할 수도 있고, 로그를 남길 수도 있다. 여러 커맨드를 구성하는 커맨드도 만들 수 있다.
3. 코드
class Invoker { private val commands = mutableListOf<Command>() fun addCommand(command: Command) { commands.add(command) } fun executeCommands() { commands.forEach { it.execute() } } }
interface Command { fun execute() }
class CommandA(private val receiverA: ReceiverA): Command { override fun execute() { receiverA.actionA() receiverA.actionB() } }
class CommandB(private val receiverB: ReceiverB): Command { override fun execute() { receiverB.actionA() receiverB.actionB() receiverB.actionC() } }
class ReceiverA { fun actionA() { println("ReceiverA: action") } fun actionB() { println("ReceiverA: actionB") } }
class ReceiverB(private val text: String) { fun actionA() { println("ReceiverB: actionA + $text") } fun actionB() { println("ReceiverB: actionB + $text") } fun actionC() { println("ReceiverB: actionC + $text") } }
fun main() { val invoker = Invoker() val commandA = CommandA(ReceiverA()) val commandB = CommandB(ReceiverB("commandPattern")) invoker.addCommand(commandA) invoker.addCommand(commandB) invoker.executeCommands() }
4. 실행 결과
반응형