헤드 퍼스트 디자인 패턴 | 에릭 프리먼 | 한빛미디어- 교보ebook

14가지 GoF 필살 패턴!, 경력과 세대를 넘어 오랫동안 객체지향 개발자의 성장을 도와준 디자인 패턴 교과서의 화려한 귀환! 》 2005년부터 디자인 패턴 도서 분야 부동의 1위 》 디자인 패턴의 고

ebook-product.kyobobook.co.kr

메소드 호출을 캡슐화

커맨드 패턴은 작업을 요청하는 쪽과 작업을 처리하는 쪽을 분리할 수 있다.

 

커맨드 객체는 특정 객체에 관한 특정 작업 요청을 캡슐화한다.

커맨드 패턴 소개

구성요소 클라이언트, 인보커, 커맨드, 리시버

클라이언트는 커맨드 객체를 생성한다.

커맨드 객체 안에는 리시버가 있다.

리시버는 실제로 동작을 수행하는 역할을 한다.

커맨드 객체는 인보커에 저장된다. 

인보커는 클라이언트 요청으로 저장된 커맨드 객체를 실행한다.

커맨드 객체에 동작은 리시버가 한다.

 

public class CommandTest {
	//리시버
	static class Light {
		public Light() {	}
		public void on() {
			System.out.println("Light is on");
		}
		public void off() {
			System.out.println("Light is off");
		}
	}
	static  class GarageDoor {
		public GarageDoor() {
		}

		public void up() {
			System.out.println("Garage Door is Open");
		}

		public void down() {
			System.out.println("Garage Door is Closed");
		}

		public void stop() {
			System.out.println("Garage Door is Stopped");
		}

		public void lightOn() {
			System.out.println("Garage light is on");
		}

		public void lightOff() {
			System.out.println("Garage light is off");
		}
	}
	
	//커맨드
	@FunctionalInterface
	static interface Command{
		void execute();
	}
	static class LightOnCommand implements Command{
		Light light;
		
		public LightOnCommand(Light light) {
			this.light = light;
		}
		public void execute() {
			light.on();
		}
	}
	static class GarageDoorOpenCommand implements Command{
		GarageDoor garageDoor;
		public GarageDoorOpenCommand(GarageDoor garageDoor) {
			this.garageDoor = garageDoor;
		}
		@Override
		public void execute() {
			garageDoor.up();
		}
	}
	//인보커
	static class SimpleRemoteControl{
		Command slot;
		public SimpleRemoteControl() {	}
		
		public void setCommand(Command slot) {
			this.slot = slot;
		}
		public void buttonWasPressed() {
			slot.execute();
		}
	}
	
	//클라이언트(편의상 main이 이 역할), 커맨드 객체 생성, 인보커에게 커맨드 객체 전달
	public static void main(String[] args) {
		//인보커, 내부에 커맨드 객체를 저장하고, 다시 요청이 오면 커맨드 객체를 실행
		SimpleRemoteControl remoteControl = new SimpleRemoteControl();
		//리시버, 실제 동작을 수행하는 객체
		Light light = new Light();
		//커맨드, 외부와  내부에 리시버에게 동작을 위임한다.
		LightOnCommand lightOnCommand = new LightOnCommand(light);
		//인보커에 커맨드 저장
		remoteControl.setCommand(lightOnCommand);
		//클라이언트가 저장한 커맨드 객체 실행 요청, 이 메서드는 단순히 리시버에 동작을 위임한다.
		remoteControl.buttonWasPressed();
		
		GarageDoor garageDoor = new GarageDoor();
		GarageDoorOpenCommand garageDoorOpenCommand = new GarageDoorOpenCommand(garageDoor);
		
		remoteControl.setCommand(garageDoorOpenCommand);
		remoteControl.buttonWasPressed();
	}

}
Light is on
Garage Door is Open

커맨드 패턴의 정의

요청 내역을 객체로 캡슐화해서 객체를 서로 다른 요청 내역에 따라 매개변수화할 수 있다.

요청을 따로 큐 같은 자료구조에 저장해 실행 전에 작업 취소 같은 기능 구현도 가능하다.

import java.util.*;

public class 심플커맨드 {
	static interface Command{
		void execute();
	}
	static class Invoker{
		//큐 예시
		private final Queue<Command> commands = new LinkedList<>();
		public void addCommand(Command command) {
			this.commands.add(command);
		}
		public void action() {
			if(!commands.isEmpty())
				commands.poll().execute();
			else System.out.println("더 이상의 요청은 없어요!");
		}
	}
	public static void main(String[] args) {
		Invoker invoker = new Invoker();
		invoker.addCommand(()->System.out.println("커맨드 객체는 요청을 캡슐화합니다."));
		invoker.addCommand(()->System.out.println("커맨드 객체는 요청을 캡슐화합니다."));
		
		invoker.action();
		invoker.action();
		invoker.action();
	}
}
커맨드 객체는 요청을 캡슐화합니다.
커맨드 객체는 요청을 캡슐화합니다.
더 이상의 요청은 없어요!

 

켜고 끄는 슬롯이 존재하는 커맨드 패턴 구현

public class CommandTest2 {
    // 리시버
    static class Light {
        String location = "";
        public Light(String location) {
            this.location = location;
        }
        public void on() {
            System.out.println(location + " light is on");
        }
        public void off() {
            System.out.println(location + " light is off");
        }
    }


    static class TV {
        String location;
        int channel;
        public TV(String location) {
            this.location = location;
        }
        public void on() {
            System.out.println("TV is on");
        }
        public void off() {
            System.out.println("TV is off");
        }
        public void setInputChannel() {
            this.channel = 3;
            System.out.println("Channel is set for VCR");
        }
    }
    static class Stereo {
        String location;
        public Stereo(String location) {
            this.location = location;
        }
        public void on() {
            System.out.println(location + " stereo is on");
        }
        public void off() {
            System.out.println(location + " stereo is off");
        }
        public void setCD() {
            System.out.println(location + " stereo is set for CD input");
        }
        public void setDVD() {
            System.out.println(location + " stereo is set for DVD input");
        }
        public void setRadio() {
            System.out.println(location + " stereo is set for Radio");
        }
        public void setVolume(int volume) {
            // code to set the volume
            // valid range: 1-11 (after all 11 is better than 10, right?)
            System.out.println(location + " stereo volume set to " + volume);
        }
    }
    static class Hottub {
        boolean on;
        int temperature;
        public Hottub() {
        }
        public void on() {
            on = true;
        }
        public void off() {
            on = false;
        }
        public void bubblesOn() {
            if (on) {
                System.out.println("Hottub is bubbling!");
            }
        }
        public void bubblesOff() {
            if (on) {
                System.out.println("Hottub is not bubbling");
            }
        }
        public void jetsOn() {
            if (on) {
                System.out.println("Hottub jets are on");
            }
        }
        public void jetsOff() {
            if (on) {
                System.out.println("Hottub jets are off");
            }
        }
        public void setTemperature(int temperature) {
            this.temperature = temperature;
        }
        public void heat() {
            temperature = 105;
            System.out.println("Hottub is heating to a steaming 105 degrees");
        }
        public void cool() {
            temperature = 98;
            System.out.println("Hottub is cooling to 98 degrees");
        }
    }
    static class CeilingFan {
        String location = "";
        int level;
        public static final int HIGH = 2;
        public static final int MEDIUM = 1;
        public static final int LOW = 0;
        public CeilingFan(String location) {
            this.location = location;
        }
        public void high() {
            // turns the ceiling fan on to high
            level = HIGH;
            System.out.println(location + " ceiling fan is on high");
        }
        public void medium() {
            // turns the ceiling fan on to medium
            level = MEDIUM;
            System.out.println(location + " ceiling fan is on medium");
        }
        public void low() {
            // turns the ceiling fan on to low
            level = LOW;
            System.out.println(location + " ceiling fan is on low");
        }
        public void off() {
            // turns the ceiling fan off
            level = 0;
            System.out.println(location + " ceiling fan is off");
        }
        public int getSpeed() {
            return level;
        }
    }
    static class GarageDoor {
        String location;
        public GarageDoor(String location) {
            this.location = location;
        }
        public void up() {
            System.out.println(location + " garage Door is Up");
        }
        public void down() {
            System.out.println(location + " garage Door is Down");
        }
        public void stop() {
            System.out.println(location + " garage Door is Stopped");
        }
        public void lightOn() {
            System.out.println(location + " garage light is on");
        }
        public void lightOff() {
            System.out.println(location + " garage light is off");
        }
    }


    // 커맨드
    @FunctionalInterface
    static interface Command {
        void execute();
    }
    static class NoCommand implements Command {
        public void execute() {
        }
    }
    static class LightOnCommand implements Command {
        Light light;
        public LightOnCommand(Light light) {
            this.light = light;
        }
        public void execute() {
            light.on();
        }
    }
    static class LightOffCommand implements Command {
        Light light;
        public LightOffCommand(Light light) {
            this.light = light;
        }
        public void execute() {
            light.off();
        }
    }
    static class GarageDoorUpCommand implements Command {
        GarageDoor garageDoor;
        public GarageDoorUpCommand(GarageDoor garageDoor) {
            this.garageDoor = garageDoor;
        }
        public void execute() {
            garageDoor.up();
        }
    }
    static class GarageDoorDownCommand implements Command {
        GarageDoor garageDoor;
        public GarageDoorDownCommand(GarageDoor garageDoor) {
            this.garageDoor = garageDoor;
        }
        public void execute() {
            garageDoor.up();
        }
    }
    static class StereoOnWithCDCommand implements Command {
        Stereo stereo;
        public StereoOnWithCDCommand(Stereo stereo) {
            this.stereo = stereo;
        }
        public void execute() {
            stereo.on();
            stereo.setCD();
            stereo.setVolume(11);
        }
    }
    static class StereoOffCommand implements Command {
        Stereo stereo;
        public StereoOffCommand(Stereo stereo) {
            this.stereo = stereo;
        }
        public void execute() {
            stereo.off();
        }
    }
    static class CeilingFanOnCommand implements Command {
        CeilingFan ceilingFan;
        public CeilingFanOnCommand(CeilingFan ceilingFan) {
            this.ceilingFan = ceilingFan;
        }
        public void execute() {
            ceilingFan.high();
        }
    }
    static class CeilingFanOffCommand implements Command {
        CeilingFan ceilingFan;
        public CeilingFanOffCommand(CeilingFan ceilingFan) {
            this.ceilingFan = ceilingFan;
        }
        public void execute() {
            ceilingFan.off();
        }
    }
    static class LivingroomLightOnCommand implements Command {
        Light light;
        public LivingroomLightOnCommand(Light light) {
            this.light = light;
        }
        public void execute() {
            light.on();
        }
    }
    static class LivingroomLightOffCommand implements Command {
        Light light;
        public LivingroomLightOffCommand(Light light) {
            this.light = light;
        }
        public void execute() {
            light.off();
        }
    }
    static class HottubOnCommand implements Command {
        Hottub hottub;
        public HottubOnCommand(Hottub hottub) {
            this.hottub = hottub;
        }
        public void execute() {
            hottub.on();
            hottub.heat();
            hottub.bubblesOn();
        }
    }
    static class HottubOffCommand implements Command {
        Hottub hottub;
        public HottubOffCommand(Hottub hottub) {
            this.hottub = hottub;
        }
        public void execute() {
            hottub.cool();
            hottub.off();
        }
    }
    // 인보커
    static class RemoteControl {
        Command[] onCommands;
        Command[] offCommands;
        public RemoteControl() {
            onCommands = new Command[7];
            offCommands = new Command[7];
            Command noCommand = new NoCommand();
            for (int i = 0; i < offCommands.length; i++) {
                onCommands[i] = noCommand;
                offCommands[i] = noCommand;
            }
        }
        public void setCommand(int slot, Command onCommand, Command offCommand) {
            onCommands[slot] = onCommand;
            offCommands[slot] = offCommand;
        }
        public void onButtonWasPushed(int slot) {
            onCommands[slot].execute();
        }
        public void offButtonWasPushed(int slot) {
            offCommands[slot].execute();
        }
        @Override
        public String toString() {
            StringBuilder sb = new StringBuilder();
            sb.append("\n------ 리모컨 ------\n");
            for (int i = 0; i < offCommands.length; i++) {
                sb.append("[slot" + i + "]" + onCommands[i].getClass().getSimpleName());
                sb.append("    " + offCommands[i].getClass().getSimpleName()+"\n");
            }
            return sb.toString();
        }
    }
    // 클라이언트, 커맨드 객체 생성, 인보커에게 커맨드 객체 전달
    public static void main(String[] args) {
        RemoteControl remoteControl = new RemoteControl();
         
        Light livingRoomLight = new Light("Living Room");
        Light kitchenLight = new Light("Kitchen");
        CeilingFan ceilingFan= new CeilingFan("Living Room");
        GarageDoor garageDoor = new GarageDoor("Garage");
        Stereo stereo = new Stereo("Living Room");
       
        LightOnCommand livingRoomLightOn =
                new LightOnCommand(livingRoomLight);
        LightOffCommand livingRoomLightOff =
                new LightOffCommand(livingRoomLight);
        LightOnCommand kitchenLightOn =
                new LightOnCommand(kitchenLight);
        LightOffCommand kitchenLightOff =
                new LightOffCommand(kitchenLight);


        CeilingFanOnCommand ceilingFanOn =
                new CeilingFanOnCommand(ceilingFan);
        CeilingFanOffCommand ceilingFanOff =
                new CeilingFanOffCommand(ceilingFan);


        GarageDoorUpCommand garageDoorUp =
                new GarageDoorUpCommand(garageDoor);
        GarageDoorDownCommand garageDoorDown =
                new GarageDoorDownCommand(garageDoor);


        StereoOnWithCDCommand stereoOnWithCD =
                new StereoOnWithCDCommand(stereo);
        StereoOffCommand  stereoOff =
                new StereoOffCommand(stereo);


        remoteControl.setCommand(0, livingRoomLightOn, livingRoomLightOff);
        remoteControl.setCommand(1, kitchenLightOn, kitchenLightOff);
        remoteControl.setCommand(2, ceilingFanOn, ceilingFanOff);
        remoteControl.setCommand(3, stereoOnWithCD, stereoOff);


        System.out.println(remoteControl);


        remoteControl.onButtonWasPushed(0);
        remoteControl.offButtonWasPushed(0);
        remoteControl.onButtonWasPushed(1);
        remoteControl.offButtonWasPushed(1);
        remoteControl.onButtonWasPushed(2);
        remoteControl.offButtonWasPushed(2);
        remoteControl.onButtonWasPushed(3);
        remoteControl.offButtonWasPushed(3);
    }
}
------ 리모컨 ------
[slot0]LightOnCommand LightOffCommand
[slot1]LightOnCommand LightOffCommand
[slot2]CeilingFanOnCommand CeilingFanOffCommand
[slot3]StereoOnWithCDCommand StereoOffCommand
[slot4]NoCommand NoCommand
[slot5]NoCommand NoCommand
[slot6]NoCommand NoCommand
Living Room light is on
Living Room light is off
Kitchen light is on
Kitchen light is off
Living Room ceiling fan is on high
Living Room ceiling fan is off
Living Room stereo is on
Living Room stereo is set for CD input
Living Room stereo volume set to 11
Living Room stereo is off

즐겨찾기 처럼 슬롯에 저장해둔 커맨드 객체는 언제든지 호출할 수 있다.

4~6 슬롯에 NoCommand 객체는 아무런 일도 안한다. 일종의 Null 객체로 이렇게 구현해두면 호출하는 쪽에서 Null 걱정을 을 할필요가 없다.

 

실행 했던 커맨드 되돌리기 

public class CommandTest3 {
    // 리시버
    static class Light {
        String location = "";
        public Light(String location) {
            this.location = location;
        }
        public void on() {
            System.out.println(location + " light is on");
        }
        public void off() {
            System.out.println(location + " light is off");
        }
    }
    static class TV {
        String location;
        int channel;
        public TV(String location) {
            this.location = location;
        }
        public void on() {
            System.out.println("TV is on");
        }
        public void off() {
            System.out.println("TV is off");
        }
        public void setInputChannel() {
            this.channel = 3;
            System.out.println("Channel is set for VCR");
        }
    }
    static class Stereo {
        String location;
        public Stereo(String location) {
            this.location = location;
        }
        public void on() {
            System.out.println(location + " stereo is on");
        }
        public void off() {
            System.out.println(location + " stereo is off");
        }
        public void setCD() {
            System.out.println(location + " stereo is set for CD input");
        }
        public void setDVD() {
            System.out.println(location + " stereo is set for DVD input");
        }
        public void setRadio() {
            System.out.println(location + " stereo is set for Radio");
        }
        public void setVolume(int volume) {
            // code to set the volume
            // valid range: 1-11 (after all 11 is better than 10, right?)
            System.out.println(location + " stereo volume set to " + volume);
        }
    }
    static class Hottub {
        boolean on;
        int temperature;
        public Hottub() {
        }
        public void on() {
            on = true;
        }
        public void off() {
            on = false;
        }
        public void bubblesOn() {
            if (on) {
                System.out.println("Hottub is bubbling!");
            }
        }
        public void bubblesOff() {
            if (on) {
                System.out.println("Hottub is not bubbling");
            }
        }
        public void jetsOn() {
            if (on) {
                System.out.println("Hottub jets are on");
            }
        }
        public void jetsOff() {
            if (on) {
                System.out.println("Hottub jets are off");
            }
        }
        public void setTemperature(int temperature) {
            this.temperature = temperature;
        }
        public void heat() {
            temperature = 105;
            System.out.println("Hottub is heating to a steaming 105 degrees");
        }
        public void cool() {
            temperature = 98;
            System.out.println("Hottub is cooling to 98 degrees");
        }
    }
    static class CeilingFan {
        public static final int HIGH = 3;
        public static final int MEDIUM = 2;
        public static final int LOW = 1;
        public static final int OFF = 0;
        String location;
        int speed;
        public CeilingFan(String location) {
            this.location = location;
            speed = OFF;
        }
        public void high() {
            speed = HIGH;
            System.out.println(location + " ceiling fan is on high");
        }
        public void medium() {
            speed = MEDIUM;
            System.out.println(location + " ceiling fan is on medium");
        }
        public void low() {
            speed = LOW;
            System.out.println(location + " ceiling fan is on low");
        }
        public void off() {
            speed = OFF;
            System.out.println(location + " ceiling fan is off");
        }
        public int getSpeed() {
            return speed;
        }
    }
    static class GarageDoor {
        String location;
        public GarageDoor(String location) {
            this.location = location;
        }
        public void up() {
            System.out.println(location + " garage Door is Up");
        }
        public void down() {
            System.out.println(location + " garage Door is Down");
        }
        public void stop() {
            System.out.println(location + " garage Door is Stopped");
        }
        public void lightOn() {
            System.out.println(location + " garage light is on");
        }
        public void lightOff() {
            System.out.println(location + " garage light is off");
        }
    }
    // 커맨드
    static interface Command {
        void execute();
        void undo();
    }
    static class NoCommand implements Command {
        public void execute() {
        }
        public void undo() {
        }
    }
    static class LightOnCommand implements Command {
        Light light;
        public LightOnCommand(Light light) {
            this.light = light;
        }
        public void execute() {
            light.on();
        }
        public void undo() {
            light.off();
        }
    }
    static class LightOffCommand implements Command {
        Light light;
        public LightOffCommand(Light light) {
            this.light = light;
        }
        public void execute() {
            light.off();
        }
        @Override
        public void undo() {
            light.on();
        }
    }
    static class GarageDoorUpCommand implements Command {
        GarageDoor garageDoor;
        public GarageDoorUpCommand(GarageDoor garageDoor) {
            this.garageDoor = garageDoor;
        }
        public void execute() {
            garageDoor.up();
        }
        @Override
        public void undo() {
            garageDoor.down();
        }
    }
    static class GarageDoorDownCommand implements Command {
        GarageDoor garageDoor;
        public GarageDoorDownCommand(GarageDoor garageDoor) {
            this.garageDoor = garageDoor;
        }
        public void execute() {
            garageDoor.down();
        }
        public void undo() {
            garageDoor.up();
        }
    }
    static class StereoOnWithCDCommand implements Command {
        Stereo stereo;
        public StereoOnWithCDCommand(Stereo stereo) {
            this.stereo = stereo;
        }
        public void execute() {
            stereo.on();
            stereo.setCD();
            stereo.setVolume(11);
        }
        @Override
        public void undo() {
            stereo.off();
        }
    }
    static class StereoOffCommand implements Command {
        Stereo stereo;
        int prev;
        public StereoOffCommand(Stereo stereo) {
            this.stereo = stereo;
        }
        public void execute() {
            stereo.off();
        }
        @Override
        public void undo() {
            stereo.on();
            stereo.setCD();
            stereo.setVolume(11);
        }
    }
    static class CeilingFanHighCommand implements Command {
        CeilingFan ceilingFan;
        int prevSpeed;
        public CeilingFanHighCommand(CeilingFan ceilingFan) {
            this.ceilingFan = ceilingFan;
        }
        public void execute() {
            prevSpeed = ceilingFan.getSpeed();
            ceilingFan.high();
        }
        public void undo() {
            if (prevSpeed == CeilingFan.HIGH) {
                ceilingFan.high();
            } else if (prevSpeed == CeilingFan.MEDIUM) {
                ceilingFan.medium();
            } else if (prevSpeed == CeilingFan.LOW) {
                ceilingFan.low();
            } else if (prevSpeed == CeilingFan.OFF) {
                ceilingFan.off();
            }
        }
    }
    static class CeilingFanMediumCommand implements Command {
        CeilingFan ceilingFan;
        int prevSpeed;
        public CeilingFanMediumCommand(CeilingFan ceilingFan) {
            this.ceilingFan = ceilingFan;
        }
        public void execute() {
            prevSpeed = ceilingFan.getSpeed();
            ceilingFan.medium();
        }
        public void undo() {
            if (prevSpeed == CeilingFan.HIGH) {
                ceilingFan.high();
            } else if (prevSpeed == CeilingFan.MEDIUM) {
                ceilingFan.medium();
            } else if (prevSpeed == CeilingFan.LOW) {
                ceilingFan.low();
            } else if (prevSpeed == CeilingFan.OFF) {
                ceilingFan.off();
            }
        }
    }
    static class CeilingFanLowCommand implements Command {
        CeilingFan ceilingFan;
        int prevSpeed;
        public CeilingFanLowCommand(CeilingFan ceilingFan) {
            this.ceilingFan = ceilingFan;
        }
        public void execute() {
            prevSpeed = ceilingFan.getSpeed();
            ceilingFan.low();
        }
        public void undo() {
            if (prevSpeed == CeilingFan.HIGH) {
                ceilingFan.high();
            } else if (prevSpeed == CeilingFan.MEDIUM) {
                ceilingFan.medium();
            } else if (prevSpeed == CeilingFan.LOW) {
                ceilingFan.low();
            } else if (prevSpeed == CeilingFan.OFF) {
                ceilingFan.off();
            }
        }
    }
    static class CeilingFanOffCommand implements Command {
        CeilingFan ceilingFan;
        int prevSpeed;
        public CeilingFanOffCommand(CeilingFan ceilingFan) {
            this.ceilingFan = ceilingFan;
        }
        public void execute() {
            prevSpeed = ceilingFan.getSpeed();
            ceilingFan.off();
        }
        public void undo() {
            if (prevSpeed == CeilingFan.HIGH) {
                ceilingFan.high();
            } else if (prevSpeed == CeilingFan.MEDIUM) {
                ceilingFan.medium();
            } else if (prevSpeed == CeilingFan.LOW) {
                ceilingFan.low();
            } else if (prevSpeed == CeilingFan.OFF) {
                ceilingFan.off();
            }
        }
    }
    static class LivingroomLightOnCommand implements Command {
        Light light;
        public LivingroomLightOnCommand(Light light) {
            this.light = light;
        }
        public void execute() {
            light.on();
        }
        public void undo() {
            light.off();
        }
    }
    static class LivingroomLightOffCommand implements Command {
        Light light;
        public LivingroomLightOffCommand(Light light) {
            this.light = light;
        }
        public void execute() {
            light.off();
        }
        public void undo() {
            light.on();
        }
    }
    static class HottubOnCommand implements Command {
        Hottub hottub;
        public HottubOnCommand(Hottub hottub) {
            this.hottub = hottub;
        }
        public void execute() {
            hottub.on();
            hottub.heat();
            hottub.bubblesOn();
        }
        public void undo() {
            hottub.cool();
            hottub.off();
        }
    }
    static class HottubOffCommand implements Command {
        Hottub hottub;
        public HottubOffCommand(Hottub hottub) {
            this.hottub = hottub;
        }
        public void execute() {
            hottub.cool();
            hottub.off();
        }
        @Override
        public void undo() {
            hottub.on();
            hottub.heat();
            hottub.bubblesOn();
        }
    }
   
    // 인보커
    static class RemoteControlWithUndo {
        Command[] onCommands;
        Command[] offCommands;
        Command undoCommand;
        public RemoteControlWithUndo() {
            onCommands = new Command[7];
            offCommands = new Command[7];
            Command noCommand = new NoCommand();
            for (int i = 0; i < offCommands.length; i++) {
                onCommands[i] = noCommand;
                offCommands[i] = noCommand;
            }
            undoCommand = noCommand;
        }
        public void setCommand(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) {
            offCommands[slot].execute();
            undoCommand = offCommands[slot];
        }
        public void undoButtonWasPushed() {
            undoCommand.undo();
        }
        @Override
        public String toString() {
            StringBuilder sb = new StringBuilder();
            sb.append("\n------ 리모컨 ------\n");
            for (int i = 0; i < offCommands.length; i++) {
                sb.append("[slot" + i + "]" + onCommands[i].getClass().getSimpleName());
                sb.append("    " + offCommands[i].getClass().getSimpleName() + "\n");
            }
            sb.append("[undo] " + undoCommand.getClass().getSimpleName() + "\n");
            return sb.toString();
        }
    }
    // 클라이언트, 커맨드 객체 생성, 인보커에게 커맨드 객체 전달
    public static void main(String[] args) {
        RemoteControlWithUndo remoteControl = new RemoteControlWithUndo();
        Light livingRoomLight = new Light("Living Room");
        LightOnCommand livingRoomLightOn = new LightOnCommand(livingRoomLight);
        LightOffCommand livingRoomLightOff = new LightOffCommand(livingRoomLight);
        remoteControl.setCommand(0, livingRoomLightOn, livingRoomLightOff);
        remoteControl.onButtonWasPushed(0);
        remoteControl.offButtonWasPushed(0);
        System.out.println(remoteControl);
        remoteControl.undoButtonWasPushed();
        remoteControl.offButtonWasPushed(0);
        remoteControl.onButtonWasPushed(0);
        System.out.println(remoteControl);
        remoteControl.undoButtonWasPushed();
        CeilingFan ceilingFan = new CeilingFan("Living Room");
        CeilingFanMediumCommand ceilingFanMedium = new CeilingFanMediumCommand(ceilingFan);
        CeilingFanHighCommand ceilingFanHigh = new CeilingFanHighCommand(ceilingFan);
        CeilingFanOffCommand ceilingFanOff = new CeilingFanOffCommand(ceilingFan);
        remoteControl.setCommand(0, ceilingFanMedium, ceilingFanOff);
        remoteControl.setCommand(1, ceilingFanHigh, ceilingFanOff);
        remoteControl.onButtonWasPushed(0);
        remoteControl.offButtonWasPushed(0);
        System.out.println(remoteControl);
        remoteControl.undoButtonWasPushed();
        remoteControl.onButtonWasPushed(1);
        System.out.println(remoteControl);
        remoteControl.undoButtonWasPushed();
    }
}
Living Room light is on
Living Room light is off
------ 리모컨 ------
[slot0]LightOnCommand LightOffCommand
[slot1]NoCommand NoCommand
[slot2]NoCommand NoCommand
[slot3]NoCommand NoCommand
[slot4]NoCommand NoCommand
[slot5]NoCommand NoCommand
[slot6]NoCommand NoCommand
[undo] LightOffCommand
Living Room light is on
Living Room light is off
Living Room light is on
------ 리모컨 ------
[slot0]LightOnCommand LightOffCommand
[slot1]NoCommand NoCommand
[slot2]NoCommand NoCommand
[slot3]NoCommand NoCommand
[slot4]NoCommand NoCommand
[slot5]NoCommand NoCommand
[slot6]NoCommand NoCommand
[undo] LightOnCommand
Living Room light is off
Living Room ceiling fan is on medium
Living Room ceiling fan is off
------ 리모컨 ------
[slot0]CeilingFanMediumCommand CeilingFanOffCommand
[slot1]CeilingFanHighCommand CeilingFanOffCommand
[slot2]NoCommand NoCommand
[slot3]NoCommand NoCommand
[slot4]NoCommand NoCommand
[slot5]NoCommand NoCommand
[slot6]NoCommand NoCommand
[undo] CeilingFanOffCommand
Living Room ceiling fan is on medium
Living Room ceiling fan is on high
------ 리모컨 ------
[slot0]CeilingFanMediumCommand CeilingFanOffCommand
[slot1]CeilingFanHighCommand CeilingFanOffCommand
[slot2]NoCommand NoCommand
[slot3]NoCommand NoCommand
[slot4]NoCommand NoCommand
[slot5]NoCommand NoCommand
[slot6]NoCommand NoCommand
[undo] CeilingFanHighCommand
Living Room ceiling fan is on medium

여러개 커맨드 한번에 실행

    static class MacroCommand implements Command{
        Command[] commands;
       
        public MacroCommand(Command[] commands) {
            this.commands = commands;
        }
        public void execute() {
            for(Command command : commands) {
                command.execute();
            }
        }
        public void undo() {
            for(Command command : commands) {
                command.undo();
            }
        }
    }




    public static void main(String[] args) {
        RemoteControl remoteControl = new RemoteControl();
        Light light = new Light("Living Room");
        TV tv = new TV("Living Room");
        Stereo stereo = new Stereo("Living Room");
        Hottub hottub = new Hottub();


        LightOnCommand lightOn = new LightOnCommand(light);
        StereoOnCommand stereoOn = new StereoOnCommand(stereo);
        TVOnCommand tvOn = new TVOnCommand(tv);
        HottubOnCommand hottubOn = new HottubOnCommand(hottub);
        LightOffCommand lightOff = new LightOffCommand(light);
        StereoOffCommand stereoOff = new StereoOffCommand(stereo);
        TVOffCommand tvOff = new TVOffCommand(tv);
        HottubOffCommand hottubOff = new HottubOffCommand(hottub);
        Command[] partyOn = { lightOn, stereoOn, tvOn, hottubOn};
        Command[] partyOff = { lightOff, stereoOff, tvOff, hottubOff};


        MacroCommand partyOnMacro = new MacroCommand(partyOn);
        MacroCommand partyOffMacro = new MacroCommand(partyOff);


        remoteControl.setCommand(0, partyOnMacro, partyOffMacro);


        System.out.println(remoteControl);
        System.out.println("--- Pushing Macro On---");
        remoteControl.onButtonWasPushed(0);
        System.out.println("--- Pushing Macro Off---");
        remoteControl.offButtonWasPushed(0);
    }
------ 리모컨 ------
[slot0]MacroCommand MacroCommand
[slot1]NoCommand NoCommand
[slot2]NoCommand NoCommand
[slot3]NoCommand NoCommand
[slot4]NoCommand NoCommand
[slot5]NoCommand NoCommand
[slot6]NoCommand NoCommand
[undo] NoCommand
--- Pushing Macro On---
Living Room light is on
Living Room stereo is on
TV is on
Channel is set for VCR
Hottub is heating to a steaming 105 degrees
Hottub is bubbling!
--- Pushing Macro Off---
Living Room light is off
Living Room stereo is off
TV is off
Hottub is cooling to 98 degrees

커맨드 객체 배열을 한 번더 커맨드 객체로 캡슐화하여한 번에 요청으로 일련의 행동을 수행 할 수 있다.

 

핵심요약

커맨드 패턴을 사용하면 요청하는 객체와 요청을 수행하는 객체를 분리할 수 있다.

핵심은 커맨드 객체이며, 커맨드 객체는 실제 행동을 수행하는 리시버를 캡슐화한다.

 

+ Recent posts