apple/DesignPattern, Architecture
Swift 디자인패턴 Command Pattern (복합체 패턴)
lgvv
2022. 7. 5. 19:45
Swift 디자인패턴 Command Pattern (복합체 패턴)
Command 패턴은 행동 패턴 중 하나로, 특정 작업을 수행하기 위한 정보를 명령 객체에 캡슐화하는 방식.
히스토리
- 2022-07-05: 디자인 패턴 스터디 정리
- 2024-11-26: 포스팅 글 재정리 및 조금 더 실용적인 예제 코드로 변경
Command Pattern
Command Pattern은 일반적으로 3개지 개념으로 구성됨
- Command: 특정 작업을 수행하는 메서드를 호출하는 객체. 실행할 작업에 대한 정보를 포함
- Invoker(호출자): Command 객체를 호출하여 작업을 실행하는 역할. Invoker는 명령을 실행하기 위해 Command 객체를 참조
- Receiver(수신자): 실제 작업을 수행하는 객체. 명령 객체는 Receiver에게 작업을 요청
커맨드 패턴 적용을 고려할 수 있는 상황
- 어떤 실행 커맨드를 저장하고 나중에 수행해야 하는 경우에 유용
- 객체에 수행하기 위한 정보를 캡슐화하고자 하는 목적의 경우 우용
커맨드 패턴의 장점
- Command를 캡슐화하여 매개변수화 가능
- 작업에 큐를 활용하여 처리가능하고 중간에서 로그를 남길수도 있음
- 명령 객체를 사용해 이전 작업을 취소하는 작업 가능
사용 예시
- 텍스트 편집기에서 복사, 붙여넣기, 잘라내기 기능 구현
- GUI 버튼 클릭 구현
코드 예제
복사, 잘라내기, 붙여넣기 기능을 구현해보고자 함.
import SwiftUI
// Receiver
class TextEditor {
private var text: String = ""
func write(_ text: String) {
self.text += text
print("Current text: \(self.text)")
}
func cut() {
text = ""
print("Text cut.")
}
func copy() -> String {
return text
}
func paste(_ text: String) {
self.text += text
print("Text pasted: \(text)")
}
}
// Command Protocol
protocol Command {
func execute()
}
// Concrete Commands
class CutCommand: Command {
private let editor: TextEditor
init(editor: TextEditor) {
self.editor = editor
}
func execute() {
editor.cut()
}
}
class CopyCommand: Command {
private let editor: TextEditor
private var copiedText: String = ""
init(editor: TextEditor) {
self.editor = editor
}
func execute() {
copiedText = editor.copy()
print("Copied text: \(copiedText)")
}
func getCopiedText() -> String {
return copiedText
}
}
class PasteCommand: Command {
private let editor: TextEditor
private let text: String
init(editor: TextEditor, text: String) {
self.editor = editor
self.text = text
}
func execute() {
editor.paste(text)
}
}
// Invoker
class CommandInvoker {
private var commands: [Command] = []
func addCommand(_ command: Command) {
commands.append(command)
}
func executeCommands() {
for command in commands {
command.execute()
}
commands.removeAll()
}
}
private struct ContentView: View {
var body: some View {
Button("Execute") {
let editor = TextEditor()
let invoker = CommandInvoker()
// 문자 작성
editor.write("Hello, ")
editor.write("World!")
// 잘라내기
let cutCommand = CutCommand(editor: editor)
invoker.addCommand(cutCommand)
// 복사하기
let copyCommand = CopyCommand(editor: editor)
invoker.addCommand(copyCommand)
// 복사하기 커맨드 실행
copyCommand.execute()
// 붙여넣기
let copiedText = copyCommand.getCopiedText()
let pasteCommand = PasteCommand(editor: editor, text: copiedText)
invoker.addCommand(pasteCommand)
// 커맨드 실행
invoker.executeCommands()
}
}
}
#Preview {
ContentView()
}
(참고)
https://www.raywenderlich.com/books/design-patterns-by-tutorials/v3.0/chapters/21-command-pattern
https://refactoring.guru/ko/design-patterns/command