SW공학/디자인패턴

[SW공학 | 디자인패턴] 11. 커맨드 패턴 (Command Pattern)

revolutionarylife 2024. 11. 12. 09:00
반응형

🕹️ [SW공학 | 디자인패턴] 11. 커맨드 패턴 (Command Pattern)

목차

  • 커맨드 패턴 개요
  • 커맨드 패턴의 필요성
  • 커맨드 패턴의 구조
  • 커맨드 패턴 예제
  • 커맨드 패턴의 장점과 단점
  • 마무리

커맨드 패턴 개요

안녕하세요! 오늘은 작업을 객체로 캡슐화하여 요청과 수행을 분리하는 커맨드 패턴(Command Pattern)에 대해 알아보겠습니다. 커맨드 패턴은 행동 패턴(Behavioral Pattern) 중 하나로, 요청을 커맨드 객체로 캡슐화하여 여러 작업을 구성할 수 있게 합니다.

이 패턴을 사용하면 작업 요청과 실행을 분리하여 명령을 취소하거나 되돌리는 기능을 쉽게 구현할 수 있습니다.


커맨드 패턴의 필요성

UI에서 버튼 클릭, 키보드 입력, 메뉴 선택과 같은 작업을 처리할 때, 명령을 독립적으로 관리하고 실행 기록을 남기려면 코드가 복잡해질 수 있습니다. 커맨드 패턴을 사용하면 각 명령을 객체로 분리하여, 작업을 쉽게 관리하고 추적할 수 있습니다.


커맨드 패턴의 구조

커맨드 패턴은 Command (명령 인터페이스), ConcreteCommand (구체적인 명령), Receiver (수행자), Invoker (명령 호출자)로 구성됩니다.

  • Command (명령 인터페이스)
    • 명령 실행 메서드인 execute()를 정의하여, 구체적인 명령들이 동일한 인터페이스를 통해 실행됩니다.
  • ConcreteCommand (구체적인 명령)
    • Command 인터페이스를 구현하여 구체적인 명령을 정의하고, 해당 명령을 수행할 Receiver 객체를 보유합니다.
  • Receiver (수행자)
    • ConcreteCommand가 호출할 실제 작업을 수행하는 객체로, 명령의 구체적인 동작을 실행합니다.
  • Invoker (명령 호출자)
    • 명령 객체를 저장하고 실행하며, 보통 UI의 버튼이나 입력 장치와 같은 역할을 합니다.

커맨드 패턴 예제

아래 예제는 리모컨을 사용하여 전등을 켜고 끄는 작업을 커맨드 패턴으로 구현한 것입니다.

// Command 인터페이스
interface Command {
    void execute();
}

// ConcreteCommand: 전등을 켜는 명령
class LightOnCommand implements Command {
    private Light light;

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

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

// ConcreteCommand: 전등을 끄는 명령
class LightOffCommand implements Command {
    private Light light;

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

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

// Receiver: 전등 클래스
class Light {
    public void turnOn() {
        System.out.println("전등이 켜졌습니다.");
    }

    public void turnOff() {
        System.out.println("전등이 꺼졌습니다.");
    }
}

// Invoker: 리모컨 클래스
class RemoteControl {
    private Command command;

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

    public void pressButton() {
        command.execute();
    }
}

// 클라이언트 코드
public class CommandPatternExample {
    public static void main(String[] args) {
        Light light = new Light();
        Command lightOn = new LightOnCommand(light);
        Command lightOff = new LightOffCommand(light);

        RemoteControl remote = new RemoteControl();
        
        remote.setCommand(lightOn);
        remote.pressButton(); // 출력: 전등이 켜졌습니다.

        remote.setCommand(lightOff);
        remote.pressButton(); // 출력: 전등이 꺼졌습니다.
    }
}

출력 결과:

전등이 켜졌습니다.
전등이 꺼졌습니다.

예제 설명

  • Command 인터페이스: execute() 메서드를 정의하여 모든 명령이 동일한 방식으로 호출됩니다.
  • LightOnCommand, LightOffCommand (ConcreteCommand): 각 명령 클래스는 Command 인터페이스를 구현하여 전등을 켜고 끄는 동작을 수행합니다.
  • Light (Receiver): 실제 작업을 수행하는 전등 클래스입니다. turnOn() turnOff() 메서드로 전등의 상태를 변경합니다.
  • RemoteControl (Invoker): 명령을 설정하고 실행하는 리모컨 클래스입니다. setCommand()로 명령을 설정하고, pressButton()으로 명령을 실행합니다.

커맨드 패턴의 장점과 단점

장점

  • 유연성 증가: 다양한 명령을 독립적으로 관리할 수 있어, 명령을 추가하거나 수정하기 쉽습니다.
  • 작업 기록 및 취소 기능: 명령을 객체로 분리하여 작업 기록 및 되돌리기 기능을 구현할 수 있습니다.
  • 결합도 감소: InvokerReceiver가 직접적으로 결합되지 않고 Command 인터페이스로 상호작용하여 결합도를 낮춥니다.

단점

  • 복잡성 증가: 각 명령마다 클래스를 생성해야 하므로, 명령의 수가 많아질수록 코드가 복잡해질 수 있습니다.
  • 메모리 사용 증가: 모든 명령을 객체로 생성하므로, 명령 객체가 많아지면 메모리 사용이 증가할 수 있습니다.

마무리

커맨드 패턴은 작업을 명령 객체로 캡슐화하여 유연하게 작업을 추가, 수정, 취소할 수 있는 설계 패턴입니다. 이를 통해 명령을 손쉽게 관리하고 작업을 확장할 수 있습니다. 커맨드 패턴을 활용하여 작업을 효율적으로 처리하고 유지보수성을 높여보세요! 🕹️

반응형