Menu
Coddy logo textTech

커맨드 패턴

Coddy Java 여정의 객체 지향 프로그래밍 섹션에 포함된 레슨 — 87개 중 70번째.

커맨드 패턴(Command Pattern)은 요청을 요청에 대한 모든 정보를 포함하는 독립적인 객체로 변환하는 행동 디자인 패턴입니다. 이러한 변환을 통해 요청을 메서드 인수로 전달하거나, 요청의 실행을 지연시키거나 대기열에 넣을 수 있으며, 취소 가능한 작업을 지원할 수 있습니다.

레스토랑을 예로 들어 보겠습니다. 요리사에게 무엇을 요리할지 직접 말하는 대신, 주문서에 주문 내용을 적습니다. 웨이터(invoker)는 이 주문서(command)를 주방으로 가져가며, 주방에서는 이를 대기열에 추가하거나, 우선순위를 정하거나, 심지어 취소할 수도 있습니다. 이 패턴은 작업을 호출하는 객체와 작업을 수행하는 객체를 분리합니다.

이 패턴은 네 가지 핵심 구성 요소로 이루어져 있습니다: execute 메서드를 선언하는 Command 인터페이스, 특정 작업을 구현하는 ConcreteCommand 클래스들, 실제 작업을 수행하는 Receiver, 그리고 명령을 트리거하는 Invoker입니다:

interface Command {
    void execute();
}
class Light {  // 수신자
    public void turnOn() {
        System.out.println("Light is ON");
    }
    public void turnOff() {
        System.out.println("Light is OFF");
    }
}
class LightOnCommand implements Command {
    private Light light;
    
    public LightOnCommand(Light light) {
        this.light = light;
    }
    
    public void execute() {
        light.turnOn();
    }
}
class RemoteControl {  // 호출자 (Invoker)
    private Command command;
    
    public void setCommand(Command command) {
        this.command = command;
    }
    
    public void pressButton() {
        command.execute();
    }
}

인보커(invoker)는 어떤 작업이 수행될지 알지 못하며, 단지 execute()를 호출할 뿐입니다:

Light light = new Light();
Command lightOn = new LightOnCommand(light);

RemoteControl remote = new RemoteControl();
remote.setCommand(lightOn);
remote.pressButton();  // 출력: Light is ON

커맨드 패턴(Command Pattern)은 작업을 대기열에 추가하거나, 실행 취소/다시 실행 기능을 구현하거나, 나중에 실행할 작업을 예약해야 할 때 매우 유용합니다. 각 커맨드는 작업을 수행하는 데 필요한 모든 것을 캡슐화하므로, 시스템을 더욱 유연하고 확장 가능하게 만들어 줍니다.

challenge icon

챌린지

쉬움

커맨드 패턴(Command Pattern)을 사용하여 스마트 홈 자동화 시스템을 구축해 봅시다! 다양한 홈 기기를 커맨드를 통해 제어할 수 있는 시스템을 만들게 됩니다. 이 시스템을 통해 동작을 큐에 추가하거나 실행하고, 나중에 사용하기 위해 저장할 수도 있습니다. 마치 각 기기가 내부적으로 어떻게 작동하는지 알 필요가 없는 만능 리모컨과 같습니다.

코드는 다음 네 개의 파일로 구성됩니다:

  • Command.java: 모든 기기 커맨드가 구현할 Command 인터페이스를 정의합니다. 커맨드의 동작을 수행하는 단일 메서드 execute()를 선언해야 합니다.
  • Devices.java: 스마트 홈 기기를 나타내는 두 개의 수신자(receiver) 클래스를 생성합니다:

    Television - TV is now ON을 출력하는 powerOn() 메서드, TV is now OFF를 출력하는 powerOff() 메서드, 그리고 TV channel set to [channel]을 출력하는 setChannel(int channel) 메서드를 가집니다.

    Thermostat - Thermostat set to [temp] degrees를 출력하는 setTemperature(int temp) 메서드와 Thermostat turned OFF를 출력하는 turnOff() 메서드를 가집니다.

  • Commands.java: 기기 작업을 캡슐화하는 구체적인 커맨드 클래스들을 생성합니다:

    TVOnCommand - 생성자에서 Television 객체를 받으며, 실행 시 powerOn()을 호출합니다.

    TVOffCommand - 생성자에서 Television 객체를 받으며, 실행 시 powerOff()를 호출합니다.

    TVChannelCommand - 생성자에서 Television 객체와 int channel을 받으며, 실행 시 해당 채널로 setChannel()을 호출합니다.

    ThermostatSetCommand - 생성자에서 Thermostat 객체와 int temperature를 받으며, 실행 시 해당 값으로 setTemperature()를 호출합니다.

  • Main.java: 커맨드를 저장하는 setCommand(Command cmd) 메서드와 저장된 커맨드를 실행하는 pressButton() 메서드를 가진 RemoteControl 클래스(인보커, invoker)를 생성합니다.

    메인 메서드에서는 TV 채널 번호(정수)와 서모스탯 온도(정수)라는 두 개의 입력을 받습니다.

    TelevisionThermostat 객체를 생성합니다. RemoteControl 객체를 생성하고 다음 순서대로 커맨드 패턴을 시연합니다:

    1. TVOnCommand를 설정하고 버튼을 누릅니다.
    2. 입력받은 채널로 TVChannelCommand를 설정하고 버튼을 누릅니다.
    3. 입력받은 온도로 ThermostatSetCommand를 설정하고 버튼을 누릅니다.
    4. TVOffCommand를 설정하고 버튼을 누릅니다.

입력은 TV 채널(정수)과 서모스탯 온도(정수) 순서로 주어집니다.

예를 들어, 입력이 572인 경우 출력은 다음과 같습니다:

TV is now ON
TV channel set to 5
Thermostat set to 72 degrees
TV is now OFF

RemoteControl이 기기와 직접 상호작용하지 않고 오직 Command 인터페이스만 알고 있다는 점에 주목하세요. 각 커맨드는 동작을 수행하는 데 필요한 모든 것을 캡슐화하므로, 인보커를 변경하지 않고도 새로운 기기와 커맨드를 쉽게 추가할 수 있습니다!

직접 해보기

import java.util.Scanner;

// TODO: 다음을 포함하는 RemoteControl 클래스(invoker)를 생성하세요:
// - 명령을 저장하는 setCommand(Command cmd) 메서드
// - 저장된 명령을 실행하는 pressButton() 메서드

class RemoteControl {
    // TODO: RemoteControl 구현하기
}

class Main {
    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        
        // 입력 읽기
        int channel = scanner.nextInt();
        int temperature = scanner.nextInt();
        
        // TODO: Television과 Thermostat 생성하기
        
        // TODO: RemoteControl 생성하기
        
        // TODO: Command 패턴 시연하기:
        // 1. TVOnCommand를 설정하고 버튼을 누릅니다
        // 2. 입력받은 채널로 TVChannelCommand를 설정하고 버튼을 누릅니다
        // 3. 입력받은 온도로 ThermostatSetCommand를 설정하고 버튼을 누릅니다
        // 4. TVOffCommand를 설정하고 버튼을 누릅니다
        
        scanner.close();
    }
}
quiz icon실력 점검

이 레슨에는 짧은 퀴즈가 포함되어 있습니다. 레슨을 시작해 문제를 풀고 진행 상황을 기록하세요.

객체 지향 프로그래밍의 모든 레슨