본문 바로가기
Delvelopment/DesignPattern

[Design Pattern] 커맨드 패턴 (Command Pattern)

by 제제킴 2022. 7. 3.
반응형

커맨드 패턴을 (Command Pattern)을 사용하면 요청 내역을 객체로 캡슐화해서 객체를 서로 다른 요청 내역에 다라 매개변수화할 수 있습니다. 이러면 요청을 큐에 저장하거나 로그로 기록하거나 작업 취소 기능을 사용할 수 있습니다.

  • 커맨드 객체 (command object)는 일련의 행동을 특정 리시버와 연결하므로써 어떤 작업을 요청하는 쪽과 그 작업을 처리하는 쪽을 분리할 수 있다. 이 객체가 행동이 들어 있는 리시버를 캡슐화 한다.
  • 커맨드는 인보커를 매개변수화 할 수있다. 실행 중에 동적으로 매개변수화를 설정할 수도 있다.
  • 커맨드 패턴으로 작업 취소 기능도 구현이 된다.
  • 매크로 커맨드는 커먼드를 확장해서 여러 개의 커맨드를 한 번에 호출할 수 있게 해주는 가장 간편한 방법이다.
  • 커맨드 패턴을 활용해서 로그 및 트랜잭션 시스템을 구현할 수 있다. (특정 체크 포인트 이후의 모든 행복을 로그에 기록하는 방식.)

해드퍼스트 디자인패턴

public interface Command {
    void execute();
    void undo();
}
public class Light {

    String place;

    public Light(String place) {
        this.place = place;
    }

    public void on() {
    }

    ;

    public void off() {
    }

    ;

}

public class LightOnCommand implements Command {

    Light light;

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

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

    @Override
    public void undo() {
        light.off();
    }
}
public class SimpleRemoteControl {

    Command slot;

    public SimpleRemoteControl() {
    }

    /*
    * 슬롯을 가지고 제어할 명령을 설정하는 메소드
    * */
    public void setCommand(Command slot) {
        this.slot = slot;
    }

    public void buttonWasPressed() {
        slot.execute();
    }
}
public class RemoteControlTest {

    public RemoteControlTest() {

        // remote 변수가 인보커 (Invoker) 역할을 한다.
        SimpleRemoteControl remote = new SimpleRemoteControl();
        Light light = new Light("");
        // 커맨드 객체를 생성.
        LightOnCommand lightOn = new LightOnCommand(light);

        // 커맨드 객체를 인버커에 전달.
        remote.setCommand(lightOn);
        remote.buttonWasPressed();
    }
}
  • 인보커 로딩 (Invoker)
    • 클라이언트에서 커맨드 객체 생성
    • 인보커에 커맨드 객체를 저장
    • 나중에 클라이언트에서 인보커에게 그 명령을 실행하라고 요청.
    어떤 명령을 인보커에 로딩한 다음 한 번만 작업을 처리하고 커맨드 객체를 지우도록 할 수도 있고, 저장해 둔 명령을 여러 번 수행하게 할 수도 있다.
  • NoCommand 객체
    • NoCommand 객체는 일종의 널 객체 (null Object)이다. null 객체는 딱히 리턴할 객체도 없고 클라이언트가 null을 처리하지 않게 하고 싶을때 활용하면 좋다.
    • null 객체는 여러 디자인 패턴에서 유용하게 쓰인다.
package pattern.command.remote;

import pattern.command.simpleremote.Command;
import pattern.command.simpleremote.Light;

public class LightOffCommand implements Command {
    Light light;

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

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

    @Override
    public void undo() {
        light.on();
    }
}
package pattern.command.remote;

import pattern.command.simpleremote.Command;

public class NoCommand implements Command {
    public NoCommand() {
    }

    @Override
    public void execute() {

    }

    @Override
    public void undo() {

    }
}
package pattern.command.remote;

public class Stereo {

    boolean system;
    int volume;
    String cd;
    String dvd;
    String Radio;

    public void on() {
        this.system = true;
    }

    public void off() {
        this.system = false;
    }

    public void setCd(String cd) {
        this.cd = cd;
    }

    public void setDvd(String dvd) {
        this.dvd = dvd;
    }

    public void setRadio(String radio) {
        Radio = radio;
    }

    public void setVolume(int volume) {
        this.volume = volume;
    }
}
package pattern.command.remote;

import pattern.command.simpleremote.Command;

public class StereoOnWithCDCommand implements Command {

    Stereo stereo;

    public StereoOnWithCDCommand(Stereo stereo) {
        this.stereo = stereo;
    }

    @Override
    public void execute() {
        stereo.on();
        stereo.setCd("CD");
        stereo.setVolume(11);
    }

    @Override
    public void undo() {
        stereo.off();
    }
}
package pattern.command.remote;

import pattern.command.simpleremote.Light;
import pattern.command.simpleremote.LightOnCommand;

public class RemoteLoader {

    public RemoteLoader() {
        RemoteControl remoteControl = new RemoteControl();

        Light livingRoomLight = new Light("Living Room");
        Light kitchenLight = new Light("Kitchen");

        // 조명용.. 커맨드 객체
        LightOnCommand livingRoomLightOn = new LightOnCommand(livingRoomLight);
        LightOffCommand lightOffCommand = new LightOffCommand(livingRoomLight);
        LightOnCommand kitchenLightOn = new LightOnCommand(kitchenLight);
        LightOffCommand kitchenLightOff = new LightOffCommand(kitchenLight);

        // 선풍기.. 커맨드 객체

        // 차고 문.. 커맨드 객체

        // 오디오 .. 커맨드 객체

        remoteControl.setCommands(0, livingRoomLightOn, lightOffCommand);
        remoteControl.setCommands(1, kitchenLightOn, kitchenLightOff);

        System.out.println(remoteControl);

        remoteControl.onButtonWasPushed(0);
        remoteControl.offButtonWasPushed(0);
        remoteControl.onButtonWasPushed(1);
        remoteControl.offButtonWasPushed(1);
        remoteControl.undoButtonWasPushed();
    }
}
package pattern.command.remote;

import pattern.command.simpleremote.Command;

import java.util.Arrays;

public class RemoteControl {
    Command[] onCommands;
    Command[] offCommands;
    Command undoCommand;

    public RemoteControl() {
        onCommands = new Command[7];
        offCommands = new Command[7];

        Command noCommand = new NoCommand();
        for (int i = 0; i < 7; i++) {
            onCommands[i] = noCommand;
            offCommands[i] = noCommand;
        }
        undoCommand = noCommand;
    }

    public void setCommands(int slot, Command onCommand, Command offCommand) {
        onCommands[slot] = onCommand;
        offCommands[slot] = offCommand;
    }

    public void onButtonWasPushed(int slot) {
        onCommands[slot].execute();
        undoCommand = onCommands[slot];
    }

    public void offButtonWasPushed(int slot) {
        onCommands[slot].execute();
        undoCommand = offCommands[slot];
    }

    public void undoButtonWasPushed(){
        undoCommand.undo();
    }

    @Override
    public String toString() {
        StringBuffer stringBuffer = new StringBuffer();
        stringBuffer.append("\\n---------리모컨--------\\n");
        for (int i = 0; i < onCommands.length; i++) {
            stringBuffer.append("[slot " + i + "] " + onCommands[i].getClass().getSimpleName()
                    + "    " + offCommands[i].getClass().getName() + "\\n");
        }
        return stringBuffer.toString();
    }
}
반응형

댓글