💡 NOTE
커맨드 패턴을 이용하면 요구사항을 객체로 캡슐화 할 수 있으며, 매개변수를 써서 여러 가지 다른 요구사항을 집어넣을 수도 있습니다. 또한 요청 내역을 큐에 저장하거나 로그로 기록할 수도 있으며, 작업 취소 기능도 지원 가능합니다.
1.Command 인터페이스 만들기
protocol Command {
func execute()
}
2.전등을 켜기 위한 커맨드 클래스 구현
public class Light {
public func on() { print("Light On") }
public func off() { print("Light Off") }
}
//1
public class LightOnCommand: Command {
//2
let light: Light
init(light: Light) {
self.light = light
}
//3
public func execute() {
light.on()
}
}
주석 1
: 우리가 만들어야 할 리모컨은 전등을 On 할수 있어야 하므로, 클라이언트가 리모컨을 눌렀을때 전등을 on하라는 명령을 내릴 Command 인터페이스를 구현하는 LightOnCommand를 생성해주어야 합니다.주석 2
: 앞서 커맨드는 리시버(전등)을 알아야 된다고 했으므로, LightOnCommand에서는 전등을 가지고 있어야 합니다.주석 3
: LightOnCommand는 구체 클래스이므로 execute()에서 전등을 on 하라는 명령을 수행합니다.3.커맨드 객체 사용하기
public class SimpleRemoteControl {
//1
var slot: Command?
//2
func setCommand(command: Command) {
slot = command
}
//3
func buttonWasPressed() {
slot?.execute()
}
}
주석 1
: 인보커인 리모컨은 커맨드를 통해 리시버와 통신하기 때문에 커맨드 인스턴스 변수를 가지고 있어야 합니다. 다만, 구체 커맨드 클래스를 가지는 것이 아니라 Command 인터페이스를 의존하고 사용하여 의존성 역전이 이루어진 구조이어야 합니다.주석 2
: 외부에서 구체 커맨드 클래스를 주입해주기 위한 메소드가 필요합니다. 이를 통해 인보커는 단순히 무언가를 execute() 하는 역할만 하고, 자신이 구체적으로 어떤 작업을 하는지에 대해 전혀 신경쓰지 않을 수 있습니다.주석 3
: 실행 명령을 내립니다.4.리코먼을 사용해봅시다
let remote = SimpleRemoteControl()
let light = Light()
let lightOn = LightOnCommand(light: light)
remote.setCommand(command: lightOn)
remote.buttonWasPressed()
---result---
Light On
remote
상수가 되겠습니다.lightOn
상수가 되겠습니다.light
상수가 되겠습니다.remote.setCommand()
를 통해 command 구체 클래스를 주입해줍니다.remote
는 이제 lightOn
이라는 구체 커맨드 클래스에서 구현하고 있는 execute()
를 통해 전등을 on 시킬 수 있습니다.