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

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

 

Design Patterns by Tutorials, Chapter 21: Command Pattern

This is a behavioral pattern that encapsulates information to perform an action into a command object. Learn how you can model the concept of executing an action and to use this pattern whenever you want to create actions that can be executed on different

www.kodeco.com:443

https://refactoring.guru/ko/design-patterns/command

 

커맨드 패턴

/ 디자인 패턴들 / 행동 패턴 커맨드 패턴 다음 이름으로도 불립니다: 액션, 트랜잭션, Command 의도 커맨드는 요청을 요청에 대한 모든 정보가 포함된 독립실행형 객체로 변환하는 행동 디자인

refactoring.guru