ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • [Design Pattern] Command Pattern
    programing/etc 2018. 10. 29. 21:37


    안녕하세요, Einere입니다.


    오늘은 디자인 패턴중의 하나인 Command Pattern에 대해 알아보겠습니다.




    What is Command Pattern

    커맨드 패턴은 명령, 혹은 요청을 객체화하여 관리하는 패턴입니다.

    즉, "밥을 먹는다" 혹은 "운동을 한다"와 같은 명령을

    ""밥을 먹음"를 수행한다" 혹은 ""운동을 함"를 수행한다"와 같습니다.



    
    // normal method
    Person i = new Person();
    i.work();
    
    // use Command pattern
    public interface Command{
        void execute();
    }
    
    new Command(){
        @Override
        public void execute(){
            Person i = new Person();
            i.work();
        }
    }.execute() 
    
    

    코드로 표현하자면 위와 같습니다.





    Why use Command Pattern

    그렇다면 왜 귀찮게 method를 굳이 독립적인 class화하여 사용하나요?


    1. 명령을 만드는 시점과 실행시키는 시점이 다르거나 만드는 놈과 실행시키는 놈이 다를 경우입니다. 

    윈도우의 예약작업이나 linux의 cronjob 같은 걸 보면, 실행시키는 놈은 실행되는 프로그램과 실행 시점만 알죠. 그 프로그램이 무엇을 할지는 모릅니다.

    이와 같이 Command는 execute()라는 메소드만 가진 인터페이스고, 

    그것을 실행시키는 놈은 뭔지는 모르겠지만 일단 실행을 하는 것입니다.


    2. command controller을 이용해 작업의 취소 또는 재실행 등을 할 수 있게 하기 위한 것입니다. 

    여러가지 명령들을 통일성있게 관리하기 위해 Command interface를 만듭니다.

    그리고 이런 Command instance들을 모아서 관리하는 controller가 존재합니다.

    controller는 command를 추가하거나 제거하고, 각 command의 execute()를 호출하는 등의 역할을 합니다.

    예시를 한번 볼까요?



    
    public class RemoteControl {
        Command[] onCommands;
        Command[] offCommands;
        Command undoCommand;
    
        public RemoteControl() {
            onCommands = new Command[5];
            offCommands = new Command[5];
    
            NoCommand noCommand = new NoCommand();
            for (int i = 0; i < onCommands.length; i++) {
                onCommands[i] = noCommand;
            }
            undoCommand = noCommand;
        }
    
        public void setCommand(int slot, Command onCommand, Command offCommand) {
            onCommands[slot] = onCommand;
            offCommands[slot] = offCommand;
        }
    
        public void onButtonPressed(int slot) {
            onCommands[slot].execute();
            undoCommand = onCommands[slot];
        }
    
        public void offButtonPressed(int slot) {
            offCommands[slot].execute();
            undoCommand = offCommands[slot];
        }
    
        public String toString() {
            StringBuilder str = new StringBuilder();
            str.append("----- remote control -----\n");
            for (int i = 0; i < onCommands.length; i++) {
                try {
                    str.append(String.format("[slot %d] %s, %s\n", i, onCommands[i].getClass().getName(), offCommands[i].getClass().getName()));
                } catch (NullPointerException e) {
                    break;
                }
    
            }
            return str.toString();
        }
    
        public void undoButtonPressed() {
            undoCommand.undo();
        }
    }
    
    

    위의 예제는 무언가를 켜는 command와 끄는 command를 최대 5개 보유하는 controller입니다.

    정적 배열을 사용하기 때문에 command가 할당되지 않는 부분에는 NoCommand라는, 아무것도 안하는 class의 instance를 할당해줍니다.


    그리고 on버튼이 눌릴때와 off버튼이 눌릴 때, 각 command의 execute()를 호출합니다.

    그와 동시에 undoCommand에 상대 command를 할당해줍니다.


    물론, undo버튼을 누르는 경우에는 그냥 undoCommand의 execute()를 호출합니다.

    이로써 실행과 실행취소를 모두 구현할 수 있습니다.



    이와 같이 command 객체를 만들어서 따로 관리하게 하는 패턴이 Command pattern이랍니다.




    참고 : 삼실청년님의 블로그


    댓글

Designed by black7375.