명령 패턴
- 요청 자체를 캡슐화, 요청이 서로 다른 사용자를 매개변수로 만들고, 요청 대기, 로깅, 되돌릴 수 있는 연산 지원
- 연산을 호출하는 객체와 수행하는 객체의 분리
활용성
- 수행할 동작을 객체로 매개변수화 할 때
- 서로 다른 시간에 요청을 명시하고, 저장, 실행하고 싶을 때
- 실행 취소 기능을 지원할 때
- 시스템이 고장 났을 때 재적용이 가능하도록 변경 과정에 대한 로깅을 지원하고 싶을 때
- 기본적인 연산의 조합으로 만든 상위 수준 연산을 써서 시스템을 구조화 할 때
구조
요소
- Command
- ConcreteCommand
- Receiver 객체와 액션 간의 연결성 정의
- 처리 객체에 정의된 연산을 호출하도록 Execute() 구현
- Client
- ConcreteCommand 객체를 생성하고 처리 객체로 정의
- Invoker
- Receiver
협력 방법
- 사용자는 ConcreteCommand 객체를 생성하고 이를 Receiver로 지정
- Invoker는 ConcreteCommand 객체를 저장
- Invoker는 Command에 정의된 Execute() 호출
- ConcreteCommand 객체는 요청을 실제 처리할 객체에 정의된 연산 호출
장점
- Command는 연산을 호출하는 객체와 연산 수행 방법을 구현하는 객체를 분리할 수 있다.
- 명령을 여러 개 복합한 복합 명령을 만들 수 있다.
- 새로운 Command 객체를 추가하기 쉽다.
- 작업들의 지연된 실행을 구현할 수 있다.
단점
- 발송자와 수신자 사이에 완전히 새로운 레이어를 도입하기 때문에 코드가 더 복잡해질 수 있다.
예시 코드
protocol Command {
func execute()
}
class DrawingReceiver {
func drawCircle() {
print("원 그려짐")
}
func drawRectangle() {
print("사각형 그려짐")
}
}
class DrawCircleCommand: Command {
private var receiver: DrawingReceiver
init(receiver: DrawingReceiver) {
self.receiver = receiver
}
func execute() {
receiver.drawCircle()
}
}
class DrawRectangleCommand: Command {
private var receiver: DrawingReceiver
init(receiver: DrawingReceiver) {
self.receiver = receiver
}
func execute() {
receiver.drawRectangle()
}
}
class DrawingInvoker {
private var commands = [Command]()
func addCommand(command: Command) {
commands.append(command)
}
func executeCommands() {
for command in commands {
command.execute()
}
commands.removeAll()
}
}
let drawingReceiver = DrawingReceiver()
let drawingInvoker = DrawingInvoker()
let drawCircleCommand = DrawCircleCommand(receiver: drawingReceiver)
let drawRectangleCommand = DrawRectangleCommand(receiver: drawingReceiver)
drawingInvoker.addCommand(command: drawCircleCommand)
drawingInvoker.addCommand(command: drawCircleCommand)
drawingInvoker.executeCommands()
drawingInvoker.addCommand(command: drawRectangleCommand)
drawingInvoker.executeCommands()
참고