본문 바로가기
Design Pattern/행동 패턴(Behavioral patterns)

Command Pattern, 커맨드 패턴

by codeyaki 2024. 2. 27.
반응형

커맨드 패턴이란?

커맨드를 객체로 만들어서 이를 사용해 나중에 실행하거나, 반복하거나 취소할 수 있도록 하는 패턴이다.

현실에서는 음식점에 손님으로 방문해 주문을 하면 주방에 주문서를 꽂아놓는다. 요리사는 이를 보고 요리를 한다. 주문서에는 음식과 관련된 모든 정보를 가지고 있다. 이때 이 주문서가 커맨드 역할을 하는것 이다.

왜 사용해야 하는가?

  • 클라이언트는 요청을 객체로 표현하기 때문에 수신자에게 직접적으로 의존하지 않게 된다.
  • 실행 취소 및 재 실행 기능을 쉽게 구현할 수 있다.
  • 간단한 커맨드들로 복잡한 커맨드를 조합할 수 있다.
  • 기존의 코드를 건들지 않고 새 커맨드를 추가할 수 있다.

언제 사용해야 하는가?

  • 요청과 수신자를 분리하고 싶을 때
  • 요청의 로깅이 필요할 때
  • 늦게 실행하거나 실행 취소 및  재실행기능이 필요할 때

구현 예시(자바)

기초적인 단계로 커맨드 부분만 구현해 보도록 하겠다. 

자바 콘솔창에서 문자를 추가하거나 색상을 바꿔보도록 하겠다.

먼저 커맨드 인터페이스를 만들어주자.

package com.example.designpattern.behavioral.commandv2.command;

public interface Command {
    void run();
}
  • run에는 앞으로 커맨드가 실행하는 메서드들을 구현할 것이다.

 

해당 인터페이스를 토대로 색상을 변경하는 커맨드와 문자를 출력하는 커맨드를 추가해 주었다.

 

package com.example.designpattern.behavioral.commandv2.command;

public class ColorCommand implements Command {
    public enum Color {
        BLACK("\u001B[30m"), RED("\u001B[31m"),
        GREEN("\u001B[32m"), YELLOW("\u001B[33m"),
        BLUE("\u001B[34m"), PURPLE("\u001B[35m"),
        CYAN("\u001B[36m"), WHITE("\u001B[37m");

        private final String code;

        Color(String code) {
            this.code = code;
        }

        public String getCode() {
            return code;
        }
    }

    private Color color;

    public ColorCommand(Color color) {
        this.color = color;
    }

    @Override
    public void run() {
        System.out.print(color.getCode());
    }
}

 

package com.example.designpattern.behavioral.commandv2.command;

import com.example.designpattern.behavioral.commandv2.command.Command;

public class PrintCommand implements Command {
    private String content;

    public PrintCommand(String content) {
        this.content = content;
    }

    @Override
    public void run() {
        System.out.println(content);
    }
}

 

그 뒤에 커맨드들을 담고 있을 커맨드그룹을 생성해 주었다.

package com.example.designpattern.behavioral.commandv2.command;

import java.util.ArrayList;
import java.util.List;

public class CommandGroup implements Command {
    private List<Command> commands = new ArrayList<>();

    public void add(Command command) {
        commands.add(command);
    }

    public Command pop(){
        int last = commands.size() - 1;
        Command popCommand = commands.get(last);
        commands.remove(last);
        return popCommand;
    }

    @Override
    public void run() {
        int size = commands.size();
        for (Command command : commands) {
            command.run();
        }
    }
}

 

이제 클라이언트들은 실행했던 명령들을 손쉽게 반복하고 명령을 취소했다가 다시 실행시킬 수 있게 되었다.

 

package com.example.designpattern.behavioral.commandv2;

import com.example.designpattern.behavioral.commandv2.command.ColorCommand;
import com.example.designpattern.behavioral.commandv2.command.Command;
import com.example.designpattern.behavioral.commandv2.command.CommandGroup;
import com.example.designpattern.behavioral.commandv2.command.PrintCommand;

public class CommandClient {
    public static void main(String[] args) {
        CommandGroup commandGroup = new CommandGroup();
        PrintCommand printCommand = new PrintCommand("안녕하세요!");

        commandGroup.add(new ColorCommand(ColorCommand.Color.GREEN));
        commandGroup.add(printCommand);
        commandGroup.add(new ColorCommand(ColorCommand.Color.RED));
        commandGroup.add(printCommand);
        commandGroup.add(printCommand);
        commandGroup.add(new ColorCommand(ColorCommand.Color.CYAN));
        commandGroup.add(printCommand);
        commandGroup.run();

        System.out.println("===== 명령 취소 해보기 =====");
        Command popCommand = commandGroup.pop();
        commandGroup.run();

        System.out.println("==== 취소한 명령 다시 실행하기 ====");
        commandGroup.add(popCommand);
        commandGroup.run();

    }
}

 

실행결과

  • 결과를 보면 마지막 실행을 취소했다가 다시 실행하는 것을 볼 수 있다.
반응형