티스토리 뷰

커맨드 패턴이란?

커맨드 패턴은 객체의 메서드(행위)를 클래스로 만들어 캡슐화한 패턴이다. 즉, 실행될 기능을 캡슐화함으로써 주어진 여러 기능을 실행할 수 있는 재사용성이 높은 클래스를 설계하는 것이다. 실행될 기능을 캡슐화함으로써 기능의 실행을 요구하는 호출자 Invoker 클래스와 실제 기능을 수행하는 수신자 Receiver 클래스 사이의 의존성을 제거한다. 따라서 실행될 기능의 변경에도 호출자 클래스를 수정 없이 그대로 사용할 수 있도록 해준다. 또한, 작업 요청 자체가 객체가 되기 때문에, 다른 객체처럼 '작업 요청' 자체를 저장하고, 복구하고, 확장할 수 있다.

커맨드 패턴 사용 법

  • Command
    • 실행될 기능에 대한 인터페이스
    • 실행될 기능을 execute 메서드로 선언
  • ConcreteCommand
    • 실제로 실행되는 기능을 구현
    • 즉, Command라는 인터페이스를 구현
  • Invoker
    • 기능의 실행을 요청하는 호출자 클래스
    • Command 객체를 캡슐화해 요청을 처리하기 위해 커맨드 객체에 요청을 전달
  • Receiver
    • ConcreteCommand에서 execute메서드를 구현할 때 필요한 클래스
    • ConcreteCommand의 기능을 실행하기 위해 사용하는 수신자 클래스
// Command 인터페이스
public interface Command {
    void execute();
}

// Receiver 클래스
public class Receiver {
    public void action() {
        System.out.println("Action has been taken.");
    }
}

// ConcreteCommand 클래스
public class ConcreteCommand implements Command {
    private Receiver receiver;

    public ConcreteCommand(Receiver receiver) {
        this.receiver = receiver;
    }

    @Override
    public void execute() {
        receiver.action();
    }
}

// Invoker 클래스
public class Invoker {
    private Command command;

    public void setCommand(Command command) {
        this.command = command;
    }

    public void executeCommand() {
        command.execute();
    }
}
// Client 클래스
public class Client {
    public static void main(String[] args) {
        Receiver receiver = new Receiver();
        Command command = new ConcreteCommand(receiver);
        Invoker invoker = new Invoker();

        invoker.setCommand(command);
        invoker.executeCommand();
    }
}

 


패턴 사용 시기

  • 클라이언트가 요청을 발생시키는 주체와 그 요청을 수행하는 주체를 분리하고 싶을 때 
  • 특정 요청에 대한 실행 취소(Undo) 및 재실행(Redo) 기능이 필요한 경우
  • 연산을 수행하는 작업을 추가, 변경하기 용이하게 하고자 할 때

패턴 장점

  • 커맨드 패턴은 연산과 실행 책임을 개별 클래스로 분리함으로써 각 클래스가 단일 책임을 가진다.
  • 새로운 커맨드를 쉽게 추가할 수 있으며, 기존 코드를 변경하지 않고도 새로운 기능을 구현할 수 있다.
  • 발신자와 수신자 사이의 결합도가 낮아져, 시스템 유연성이 증가. 커맨드 객체를 교체하거나 변경하기 쉽다.

패턴 단점

  • 각각의 개별 커맨드에 대한 클래스를 생성해야 하므로 클래스의 수가 늘어나고, 시스템이 복잡해질 수 있다.
  • 단순한 연산에 커맨드 패턴을 사용하면 오히려 설계가 과도하게 복잡해질 수 있다.