검수요청.png검수요청.png

커맨드패턴

위키원
Asadal (토론 | 기여)님의 2020년 8월 21일 (금) 21:33 판
(차이) ← 이전 판 | 최신판 (차이) | 다음 판 → (차이)
이동: 둘러보기, 검색

커맨드패턴(Command pattern)은 요청을 객체의 형태로 캡슐화하여 사용자가 보낸 요청을 나중에 이용할 수 있도록 매서드 이름, 매개변수 등 요청에 필요한 정보를 저장 또는 로깅, 취소할 수 있게 하는 패턴이다.[1]

특징

커맨드 패턴에는 명령(command), 수신자(receiver), 발동자(invoker), 클라이언트(client)의 네개의 용어가 항상 따른다. 커맨드 객체는 수신자 객체를 가지고 있으며, 수신자의 메서드를 호출하고, 이에 수신자는 자신에게 정의된 메서드를 수행한다. 커맨드 객체는 별도로 발동자 객체에 전달되어 명령을 발동하게 한다. 발동자 객체는 필요에 따라 명령 발동에 대한 기록을 남길 수 있다. 한 발동자 객체에 다수의 커맨드 객체가 전달될 수 있다. 클라이언트 객체는 발동자 객체와 하나 이상의 커맨드 객체를 보유한다. 클라이언트 객체는 어느 시점에서 어떤 명령을 수행할지를 결정한다. 명령을 수행하려면, 클라이언트 객체는 발동자 객체로 커맨드 객체를 전달한다. [1]

커맨드 패턴 클래스 다이어그램

예시

  • 만능 버튼 만들기 : 버튼이 눌리면 램프의 불이 켜지는 프로그램 [2]
 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); // 버튼 클래스의 pressed가 호출되면 생성자를 통해 전달받은 램프 객체의 turnOn()을 호출해 불을 켠다. lampButton.pressed(); } }

문제점

  • 버튼을 눌렀을 때 다른 기능을 실행하는 경우[2]
궁금점 문제점
버튼을 눌렀을때 알람이 시작되게 하려면? * 새로운 기능으로 변경하려고 기존코드의 내용을 수정해야 하므로 OCP에 위배된다.
* Button 클래스의 pressed() 전체를 변경해야한다.
 public class Alarm {
   public void start(){ System.out.println("Alarming"); }
 }
 public class Button {
   private Alarm theAlarm;
   public Button(Alarm theAlarm) { this.theAlarm = theAlarm; }
   public void pressed() { theAlarm.start(); }
 } 
public class Client { public static void main(String[] args) { Alarm alarm = new Alarm(); Button alarmButton = new Button(alarm); alarmButton.pressed(); } }
  • 버튼을 누르는 동작에 따라 다른 기능을 실행하는 경우[2]
궁금점 문제점
버튼을 처음 눌렀을 때는 램프를 켜고, 두 번째 눌렀을 때는 알람을 동작하게 하려면? * 필요한 기능을 새로 추가할 때마다 Button 클래스의 코드를 수정해야 하므로 재사용하기 어렵다.
 enum Mode { LAMP, ALARM };  // Button 클래스의 코드를 수정
 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;
    }
  }
 }

해결책

  • 문제를 해결하기 위해서는 구체적인 기능을 직접 구현하는 대신 실행될 기능을 캡슐화해야 한다. [2]


Command 클래스

[2]

 public interface Command {
 public abstract void execute;
 } 

Button 클래스

[2]

 public class Button {
 private Command theCommand;
 // 생성자에서 버튼을 눌렀을 때 필요한 기능을 인지로 받는다.
 public Button(Command theCommand) { setCommand(theCommand); }
 public void setCommand(Command newCommand) { this.theCommand = newCommand; }
 // 버튼이 눌리면 주어진 Command의 execute 메서드를 호출한다.
 public void pressed() { theCommand.execute; }

Lamp, LampOnCommand 클래스

[2]

 public class Lamp {
 public void turnOn(){ System.out.println("Lamp On"); }
 }
 /* 램프를 켜는 LampOnCommand 클래스 */
 public class LampOnCommand implements Command {
 private Lamp theLamp;
 public LampOnCommand(Lamp theLamp) { this.theLamp = theLamp; }
 // Command 인터페이스의 execute 메서드
 public void execute { theLamp.turnOn(); }
 }

Alarm, AlarmStartCommand 클래스

[2]

 public class Alarm {
 public void start(){ System.out.println("Alarming"); }
 }
 /* 알람을 울리는 AlarmStartCommand 클래스 */
 public class AlarmStartCommand implements Command {
 private Alarm theAlarm;
 public AlarmStartCommand(Alarm theAlarm) { this.theAlarm = theAlarm; }
 // Command 인터페이스의 execute 메서드
 public void execute { theAlarm.start(); }
 }

클라이언트에서의 사용

[2]

  • Command 인터페이스를 구현하는 LampOnCommand와 AlarmStartCommand 객체를 Button 객체에 설정한다.
  • Button 클래스의 pressed 메서드에서 Command 인터페이스의 execute 메서드를 호출한다.
  • Command 패턴을 이용하면 Button 클래스의 코드를 변경하지 않으면서 다양한 동작을 구현할 수 있게 된다
 public class Client {
 public static void main(String[] args) {
   Lamp lamp = new Lamp();
   Command lampOnCommand = new LampOnCommand(lamp);
   Alarm alarm = new Alarm();
   Command alarmStartCommand = new AlarmStartCommand(alarm); 
Button button1 = new Button(lampOnCommand); // 램프 켜는 Command 설정 button1.pressed(); // 램프 켜는 기능 수행
Button button2 = new Button(alarmStartCommand); // 알람 울리는 Command 설정 button2.pressed(); // 알람 울리는 기능 수행 button2.setCommand(lampOnCommand); // 다시 램프 켜는 Command로 설정 button2.pressed(); // 램프 켜는 기능 수행 } }
예제 만능 버튼 클래스 다이어그램

각주

  1. 1.0 1.1 커맨드 패턴〉, 《위키백과》
  2. 2.0 2.1 2.2 2.3 2.4 2.5 2.6 2.7 2.8 커맨드 패턴예시〉, 《Design Pattern》, 2018-07-07

참고자료

같이 보기


  검수요청.png검수요청.png 이 커맨드패턴 문서는 프로그래밍에 관한 글로서 검토가 필요합니다. 위키 문서는 누구든지 자유롭게 편집할 수 있습니다. [편집]을 눌러 문서 내용을 검토·수정해 주세요.