참치코더의 꿈 메모장

디자인 패턴 / 커맨드 패턴 정리 본문

디자인 패턴

디자인 패턴 / 커맨드 패턴 정리

참치깡 2025. 9. 28. 14:40
728x90

 

 

커맨드 패턴

 

- 요청을 객체로 만든다

- 요청을 수행하는 기능(메서드 호출)을 command라는 객체로 감싼 후 , 실행/취소/저장/큐잉 등 다양한 조작을 가능하게

  한다.

 

 구조

 

1. Command 인터페이스

- 실행할 명령을 추상화 

- 취소가 필요한 경우 undo( ) 도 포함

 

2. Receiver (수신자)

- 실제 작업을 수행하는 객체

- Light (불 켜기/끄기 동작을 가짐)

 

3. ConcreteCommand (구체적인 명령 클래스)

- 특정 요청을 리시버에 위임에서 실행

- LighthOnCommand, LightOffCommand

 

4. Invoke (호출자)

- 커맨드를 실행하는 역할

- 리모컨 버튼 -> command.execute()

 

5. Client

- 어떤 명령 객체를 어떤 리시버와 연결할지 결정

 

장점

 

- 실행(Execute)과 취소(Undo) 기능을 쉽게 구현 가능

- 명령을 큐에 넣거나 로그로 저장 -> 나중에 다시 실행 가능

- 클라이언트와 실행 로직(Receiver)을 분리 -> 확장성이 향상된다.

- 요청과 실행자 분리가 쉽다.

- if-else나 switch로 분기하는 대신, 명령 객체를 등록해두고 실행만 호출하면 됨

 

단점

 

- 클래스 수가 많아질 수 있음 (명령마다 새 클래스를 만들어야 함)

 

사용 사례

 

- GUI 버튼/메뉴 동작 (버튼 클릭 -> Command 객체 실행)

- 작업 실행 취소 기능 

- 매크로 기능 (여러 명령을 차례로 실행)

 

정리

 

- 물건 이나 실체 단위가 아니라 물체가 하는 행동(명령) 단위로 클래스를 만들어서 해당 행동을 리모콘이 선택해서

  실행하는 패턴

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
// Command 인터페이스
 
public interface PaymentCommand {
    void pay(int amount);
}
 
// Receiver
 
public class CardService {
    public void process(int amount) {
        System.out.println("카드 결제" + amount);
    }
}
 
public class KaKaoPayService {
    public void process(int amount) {
        System.out.println("카카오페이 결제: " + amount);
    }
}
 
// ConcreteCommand
// 각 결제 행위마다 클래스 생성
 
public class CardPaymentCommand implements PaymentCommand {
    private CardService cardService;
 
    public CardPaymentCommand(CardService cardService){
        this.cardService = cardService;
    }
 
    public void pay(int amount){
        cardService.process(amount);
    }
}
 
 
public class KaKaoPayCommand implements PaymentCommand {
    private kakaoPayService kakaoPayService;
    
    public KakaoPayCommand(KakaoPayService kakaoPayService){
        this.kakaoPayService = kakaoPayService;
    }
 
    public void pay(int amount) {
        kakaoPayService.process(amount);
    }
}
 
 
//Invoker
// 리모컨으로 생각하면 편안하다
 
@Service
public class PaymentInvoker {
    private final Map<String, paymentCommand> commandMap = new HashMap<>();
 
    public void register(String method, PaymentCommand command){
        commandMap.put(method, command);
    }
 
    public void execute(String method, int amount){
        PaymentCommand command = commandMap.get(method);
 
        if(command != null) {
            command.pay(amount);
        } else {
            throw new IllegalArgumentException("지원하지 않는 결제 수단: " + method);
        }
    }
}
 
 
// client (설정)
 
@Configuration
public class PaymentConfig {
 
    @Bean
    public PaymentInvoke paymentInvoker(
            CardService cardService,
            KakaoPayService kakaoPayService) {
 
            PaymentInvoker invoker = new PaymentInvoker();
            invoker.register("card"new CardPaymentCommand(cardService));
            invoker.register("kakao"new KakaoPayCommand(kakaoPayService));
            return invoker;
 
    }
}
 
 
// Controller
 
@RestController
@RequestMapping("/pay")
public class PaymentController {
 
    private final PaymentInvoke invoker;
 
    public PaymentController(paymentInvoker invoker){
        this.invoker = invoker;
    }
 
    @PostMapping("/{method}")
    public String pay(@PathVariable String method, @RequestParam int amount){
        invoker.execute(method, amount);
        return "결제 완료";
    }
}
 
 
cs
728x90
Comments