- 객체의 세부 구현을 외부에 보일 필요가 없을 때
- undo, redo 기능이 필요할 때
- 큐를 사용하거나 로그를 남기고 싶을 떼
- Request 를 캡슐화 하기 때문에 로그 요청이나 큐를 클라이언트에 parameter 로 전달할 수 있다
- 함수를 직접 호출하는 구조가 아니기 때문에 클래스/메서드들이 서로를 자세히 알 필요가 없다
- UndoManager: UIApplication.shared.keyWindow.undoManager 로 접근할 수 있다. UITextField 와 UITextView 에서 사용한다.
- NSInvocation: NSTimer 의 내부 구현을 몰라도 target 과 selector 만 지정해 주면 사용할 수 있다.
[NSTimer timerWithTimeInterval:0.5 invocation:invocation repeats:YES];
키보드 input 에 따라 움직이는 게임 캐릭터 클래스를 만들었다.
class Character {
enum Button {
case X, Y, A, B, None
}
var input: String = "" {
didSet {
switch input {
case "x": pressed = Button.X
case "y": pressed = Button.Y
case "a": pressed = Button.A
case "b": pressed = Button.B
default: pressed = Button.None
}
update()
}
}
private var pressed = Button.None
func update() {
switch pressed {
case .A: Fire()
case .B: Jump()
case .X: Roll()
case .Y: Skill()
case .None: break
}
}
func Fire() { }
func Jump() { }
func Roll() { }
func Skill() { }
}
그런데 "유저가 키와 동작을 바꿀 수 있도록 지원해야 한다"는 새로운 스펙이 등장한다면?
캐릭터와 액션의 강한 결합을 없애고 분리할 필요가 있다.
class Action {
func Fire() { }
func Jump() { }
func Roll() { }
func Skill() { }
}
protocol Command {
func execute(action: Action)
// func undo(action: Action)
}
class CommandFire: Command {
func execute(action: Action) {
action.Fire()
}
// func undo(action: Action) {
// ...
// }
}
class CommandJump: Command {
func execute(action: Action) {
action.Jump()
}
}
class CommandRoll: Command {
func execute(action: Action) {
action.Roll()
}
}
class CommandSkill: Command {
func execute(action: Action) {
action.Skill()
}
}
class Character {
var input: String = ""
private var cFire = CommandFire()
private var cJump = CommandJump()
private var cRoll = CommandRoll()
private var cSkill = CommandSkill()
private var action = Action()
func update() {
if let command = getCommand() {
command.execute(action: action)
}
}
func getCommand() -> Command? {
switch input {
case "x": return cFire
case "y": return cJump
case "a": return cRoll
case "b": return cSkill
default: return nil
}
}
}