1. 커맨드 패턴(command pattern)

커맨드 패턴은 호출자(클라이언트 또는 호출자) 와 수신자(작업 수행 개체)에서 분리(decoupling) 하여 유연성과 확장성을 제공하는 패턴이다. 즉, 호출자의 코드를 변경하지 않고 다양한 매개변수를 사용해 다양한 명령을 생성할 수 있다. 요청을 캡슐화해서 해당 요청 안에서 수행할 동작을 설정하고 수신자를 호출할 때 호출할 행동과 필요한 파라미터에 관한 모든 정보들을 커맨드(command) 라는 인터페이스 안으로 캡슐화하기 때문에 기능을 재사용할 수 있다.

 

 

커맨드 패턴의 OCP 을 실현할 수 있는 장점이 있다. 호출자 쪽의 코드가 변경되지 않으며 기능(command) 캡슐화 및 추가할 수 있기 때문이다. 하지만, 기능(command) 가 증가할수록 복잡도가 증가할 수 있는 단점이 존재한다.

 

sample code (출처 : inflearn - 코딩으로 학습하는 GoF의 디자인 패턴)

public static void main(String[] args) {
    Button button = new Button();
    button.press(new LightOnCommand(new Light()));
    button.undo();
}


public class Button {

    private Stack<Command> commands = new Stack<>();

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

    public void undo() {
        if (!commands.isEmpty()) {
            Command command = commands.pop();
            command.undo();
        }
    }

}

public class LightOnCommand implements Command {

    private Light light;

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

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

    @Override
    public void undo() {
        new LightOffCommand(this.light).execute();
    }
}

 

2. 사용 예시

java 에서는 ExecutorService interface 에서 커맨드 패턴으로 기반을 설계되어 구현되었다. 파라미터를 Runnable interface 하위 구현체를 생성하여 행동을 정의해 기능을 동작한다.

public static void main(String[] args) {
    Light light = new Light();
    Game game = new Game();
    ExecutorService executorService = Executors.newFixedThreadPool(4);
    executorService.submit(light::on);
    executorService.submit(game::start);
    executorService.submit(game::end);
    executorService.submit(light::off);
    executorService.shutdown();
}

ExecutorService.submit

 

 

Spring 진영에서 커맨드 패턴을 기반으로 구현된 예시로는 SimpleJdbcInsert, SimpleJdbcCall 이다. insert 쿼리와 stored procedure 를 호출할 때 필요한 모든 정보를 가지고 하나의 커맨드 오브젝트를 통해 관리하고 로직이 동작하는 클래스를 별도로 정의해서 수행하고 있다.

SimpleJdbcInsert insert = new SimpleJdbcInsert(dataSource)
            .withTableName("command")
            .usingGeneratedKeyColumns("id");

    Map<String, Object> data = new HashMap<>();
    data.put("name", command.getClass().getSimpleName());
    data.put("when", LocalDateTime.now());
    insert.execute(data);

 

 

다이어그램을 확인해보면 상위에 SimpleJdbcInsertOperations interface 가 존재하며, excute() 메서드에 관해 정의되어 있다.

SimpleJdbcInsert diaram

 

Reference