본문 바로가기
CS

커맨드 패턴 (Command Pattern)

by 너츠너츠 2022. 7. 27.

커맨드 패턴은 이벤트가 발생했을 때 실행될 기능이 다양하면서도 변경이 필요한 경우에 이벤트를 발생시키는 클래스를 변경하지 않고 재사용하고자 할 때 유용하다.

 

버튼을 눌러 램프를 킨다는 상황을 가정으로 코드를 구현해보면
Button Class가 Lamp를 주입받아 버튼을 눌렀을 떄 lamp의 turnOn 함수가 실행되는 것을 확인할 수 있습니다.

public class Lamp {
    public void turnOn() {
        System.out.println("Lamp On");
    }
}

public class Button {
    private Lamp theLamp;
    
    public Button(Lamp theLamp) {
        this.theLamp = theLamp;
    }
    
    public void pressed() {
        theLamp.turnOn();
    }
}

public class Client {
    public static void main(String[] args) {
        Lamp lamp = new Lamp();
        Button lampButton = new Button(lamp);
        lampButton.pressed();
    }
}

 

이 경우 버튼을 눌렀을 때 램프가 켜지는 것 대신 다른 행동을 하고 싶을 때 코드를 수정해야한다는 문제점이 있으며 OCP에 위배됩니다.

 

버튼을 누르는 동작에 따라 다른 기능을 실행하려면 기능이 실행되는 시점에 필요한 프로그램을 선택할 수 있어야 합니다.

public class Lamp {
    public void turnOn() {
        System.out.println("Lamp On");
    }
}

public class Alarm {
    public void start() {
        System.out.println("Alarming...");
    }
}

enum Mode { LAMP, ALARM }

public class Button {
    private Lamp theLamp;
    private Alarm theAlarm;
    private Mode theMode;

    public Button(Lamp theLamp, Alarm theAlarm) {
        this.theLamp = theLamp;
        this.theAlarm = theAlarm;
    }
    
    public void setMode(Mode mode) {
        this.theMode = mode;
    }

    public void pressed() {
        switch (theMode) {
            case LAMP: 
                theLamp.turnOn();
                break;
            case ALARM:
                theAlarm.start();
                break;
        }
    }
}

public class Client {
    public static void main(String[] args) {
        Lamp lamp = new Lamp();
        Alarm alarm = new Alarm();
        Button button = new Button(lamp, alarm);
        
        button.setMode(Mode.LAMP);
        button.pressed();
        
        button.setMode(Mode.ALARM);
        button.pressed();
    }
}

버튼 Class 내에서 Mode를 설정 함에 따라 버튼을 눌렀을 때 다른 결과값이 나올 수 있습니다.하지만 이 경우에 필요한 새로운 기능을 추가할 때마다 반복적으로 코드 수정이 필요할 것입니다. 즉 이것 역시 OCP에 위배된다고 볼 수 있습니다.

 

따라서 이런 부분을 해결하기 위해서 Command라는 Interface를 Button이 가지게 설정하고 Lamp와 Alarm를 작동시키는 Command들이 Comand Interface를 상속받도록 처리하면 해결할 수 있습니다.

public interface Command {
    public abstract void execute();
}

public class Button {
    private Command theCommand;

    public Button(Command theCommand) {
        setCommand(theCommand);
    }

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

    public void pressed() {
        theCommand.execute();
    }
}

public class Lamp {
    public void turnOn() {
        System.out.println("Lamp On");
    }
}

public class LampOnCommand implements Command {
    private Lamp theLamp;

    public LampOnCommand(Lamp theLamp) {
        this.theLamp = theLamp;
    }

    public void execute() {
        theLamp.turnOn();
    }
}

public class Alarm {
    public void start() {
        System.out.println("Alarming...");
    }
}

public class AlarmOnCommand implements Command {
    private Alarm theAlarm;

    public AlarmOnCommand(Alarm theAlarm) {
        this.theAlarm = theAlarm;
    }

    public void execute() {
        theAlarm.start();
    }
}

public class Client {
    public static void main(String[] args) {
        Lamp lamp = new Lamp();
        Command lampOnCommand = new LampOnCommand(lamp);

        Button lampButton = new Button(lampOnCommand);
        lampButton.pressed();
        
        Alarm alarm = new Alarm();
        Command alarmOnCommand = new AlarmOnCommand(alarm);

        Button alarmButton = new Button(alarmOnCommand);
        alarmButton.pressed();
    }
}

 

여기서 기능을 추가하고 싶다면 어떻게 접근해야할까?

public class Lamp {
    public void turnOn() {
        System.out.println("Lamp On");
    }

    public void turnOff() {
        System.out.println("Lamp Off");
    }
}

public class LampOnCommand implements Command {
    private Lamp theLamp;

    public LampOnCommand(Lamp theLamp) {
        this.theLamp = theLamp;
    }

    public void execute() {
        theLamp.turnOn();
    }
}

public class LampOffCommand implements Command {
    private Lamp theLamp;

    public LampOnCommand(Lamp theLamp) {
        this.theLamp = theLamp;
    }

    public void execute() {
        theLamp.turnOff();
    }
}

public class Client {
    public static void main(String[] args) {
        Lamp lamp = new Lamp();
        Command lampOnCommand = new LampOnCommand(lamp);
        Command lampOffCommand = new LampOffCommand(lamp);
        
        Button lampButton = new Button(lampOnCommand);
        lampButton.pressed();

        lampButton.setCommand(lampOffCommand);
        lampButton.pressed();
    }
}

 

Lamp 객체 안에 turnOff() 함수를 만들고 Off에 해당하는 커맨드를 새롭게 생성해주면 됩니다.

 

 

반응형

'CS' 카테고리의 다른 글

데커레이터 (Decorator Pattern) 패턴  (0) 2022.08.08
옵저버 패턴 (Observer Pattern)  (0) 2022.08.02
스테이트 패턴  (0) 2022.07.22
싱글톤 패턴 (Singleton Pattern)  (0) 2022.07.18
스트래티지 패턴 (Strategy Pattern)  (0) 2022.07.06

댓글