본문 바로가기

IT/디자인 패턴(Design Pattern)

[디자인 패턴] 커맨드 패턴(Command Pattern)

1) 개요

커맨드 패턴은 해당 요청에 따라야하는 기능들을 캡슐화한 객체에 정리하여 실행할 수 있게 해주는 디자인 패턴입니다.

즉, 요청에 따르는 기능들이 다양하고 변경 및 추가 삭제가 많은 경우 요청이 발생되는 클래스를 변경하지 않고 수정할 때 매우 유용합니다.


1. 커맨드 패턴이 사용되는 경우

- 병렬처리(Parallel Processing) : 병렬로 여러 스레드에서 실행이 되어야하는 경우

- 매크로(Macro) : 특정 명령에 따른 동일한 일련의 작업을 반복적으로 수행해야 하는 경우

- 네트워킹(Networking) : 네트워크를 통해 일련의 작업을 보내야하는 경우(원격조작, 게임 캐릭터에 명령)


2. 장점

- 기존 코드를 변경하지 않고 새 명령을 추가할 수 있어 코드확장이 수월합니다.

- 호출자(invoker)와 수신자(receiver)의 결합도를 낮출 수 있습니다.


3. 단점

- 개별 명령에 대한 클래스의 수가 증가할 수 있습니다.


2) UML


- Invoker : 해당 요청에 따르는 기능의 실행을 요청하는 호출자 클래스입니다.

- Command : 실행될 기능에 대한 인터페이스로, 실행되는 기능들을 종합하는 execute를 선언합니다.

- ConcreteCommand : 실제로 실행되는 기능을 구현합니다.

- Receiver : ConcreteCommand의 execute를 구현하는 클래스로, 기능을 실행하기 위해 필요한 수신자 클래스입니다.

- Client : 요청을 전달하는 클라이언트입니다.


3) 예제


1
2
3
4
public interface Command {
    public void execute();
}
 
cs

1
2
3
4
5
6
7
8
9
public class Light {
    public void on() {
        System.out.println("Light is on");
    }
    public void off() {
        System.out.println("Light is off");
    }
}
 
cs

1
2
3
4
5
6
7
8
9
10
11
12
13
public class LightOffCommand implements Command{
    Light light;
    
    public LightOffCommand(Light light) {
        this.light = light;
    }
 
    @Override
    public void execute() {
        light.off();
    }
}
 
cs

1
2
3
4
5
6
7
8
9
10
11
12
public class LightOnCommand implements Command{
    Light light;
    
    public LightOnCommand(Light light) {
        this.light = light;
    }
 
    @Override
    public void execute() {
        light.on();
    }
}
cs

1
2
3
4
5
6
7
8
9
10
11
12
13
public class SimpleRemoteControl {
    Command slot;
    
    public SimpleRemoteControl() {}
    
    public void setCommand(Command command) {
        slot = command;
    }
    
    public void buttonWasPressed() {
        slot.execute();
    }
}
cs

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
public class Stereo {
    public void on() {
        System.out.println("Stereo is on");
    }
    public void off() {
        System.out.println("Stereo is off");
    }
    public void setCD() {
        System.out.println("Stereo is set for CD input");
    }
    public void setDVD() {
        System.out.println("Stereo is set for DVD input");
    }
    public void setRadio() {
        System.out.println("Stereo is set for Radio input");
    }
    public void setVolume(int volume) {
        System.out.println("Stereo Volume set to " + volume);
    }
}
 
cs

1
2
3
4
5
6
7
8
9
10
11
12
public class StereoOffCommand implements Command{
    Stereo stereo;
    
    public StereoOffCommand(Stereo stereo) {
        this.stereo = stereo;
    }
 
    @Override
    public void execute() {
        stereo.off();
    }
}
cs

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
public class StereoOnWithCDCommand implements Command{
    Stereo stereo;
    
    public StereoOnWithCDCommand(Stereo stereo) {
        this.stereo = stereo;
    }
    
    @Override
    public void execute() {
        stereo.on();
        stereo.setCD();
        stereo.setVolume(11);
    }
 
}
cs

1
2
3
4
5
6
7
8
9
10
11
12
13
14
public class RemoteControlTest {
    public static void main(String[] args) {
        SimpleRemoteControl remote = new SimpleRemoteControl();
        Light light = new Light();
        Stereo stereo = new Stereo();
        
        remote.setCommand(new LightOnCommand(light));
        remote.buttonWasPressed();
        remote.setCommand(new StereoOnWithCDCommand(stereo));
        remote.buttonWasPressed();
        remote.setCommand(new StereoOffCommand(stereo));
        remote.buttonWasPressed();
    }
}
cs

- References :

https://www.geeksforgeeks.org/command-pattern/

https://en.wikipedia.org/wiki/Command_pattern