커맨드(Command) 패턴

커맨드 패턴은 요청을 객체로 캡슐화하여 매개변수화하고, 이력을 관리하며, 작업을 지연하거나 취소할 수 있도록 하는 디자인 패턴입니다. 이 패턴을 사용하면 요청을 보내는 객체와 이를 수신하는 객체를 분리할 수 있어 유연성과 확장성이 증가합니다.

구성 요소

구현:

  1. Command 인터페이스를 생성합니다.
  2. 각 명령어에 해당하는 ConcreteCommand 클래스를 생성합니다.
  3. Receiver 클래스를 생성합니다.
  4. Invoker 클래스를 생성합니다.
  5. Client 클래스를 생성하여 Invoker 객체를 생성하고, ConcreteCommand 객체를 생성한 후 Invoker 객체에 전달합니다.

장점

단점

예시

전등을 끄는 명령, 전등을 키는 명령 두개와 명령을 취소할 수 있는 버튼이 있다.

Command

public interface Command {
    void execute();

    void undo();
}

ConcreteCommand

public class LightOnCommand implements Command {
    private final Light light;

    public LightOnCommand(Light light) {
        this.light = light;
    }

    @Override
    public void execute() {
        this.light.on();
    }

    @Override
    public void undo() {
        if(this.light.isOn()){
            this.light.off();
        }else{
            this.light.on();
        }
    }
}

Receiver

public class Light {

    private boolean isOn;

    public void on() {
        System.out.println("불을 켭니다.");
        this.isOn = true;
    }

    public void off() {
        System.out.println("불을 끕니다.");
        this.isOn = false;
    }

    public boolean isOn() {
        return this.isOn;
    }
}

Invoker

public class Button {

    private final Stack<Command> commandStack;

    public Button() {
        this.commandStack = new Stack<>();
    }

    public void press(Command command) {
        command.execute();
        this.commandStack.push(command);
    }

    public void undo() {
        if(this.commandStack.empty()){
            return;
        }
        this.commandStack.pop().undo();
    }
}

Client

class ButtonTest {

    @Test
    public void button_test(){
        Button button = new Button();
        button.press(new LightOnCommand(new Light()));
        button.press(new LightOnCommand(new Light()));
        button.undo();
        button.undo();
    }
}

결론

커맨드 패턴은 객체 지향 디자인 패턴 중 하나로, 실행될 명령어를 캡슐화하여 호출자와 수신자의 결합도를 낮추는 장점이 있습니다. 이 패턴은 텍스트 에디터, 게임, 리모컨 등에서 사용될 수 있으며, 명령어의 실행 취소와 재실행이 가능하다는 점에서 유용합니다.

예제는 이곳 에서 확인하실수 있습니다.