Command

GamSa Ham·2022년 12월 4일
0

GoF디자인패턴

목록 보기
20/22

의도 :

  • 요청(실행 기능) 자체를 캡슐화함

⇒ 재사용성 증가

⇒ 호출자와 수신자 클래스 사이의 의존성 제거

  • 요청이 서로 다른 사용자를 매개변수로 만들고 요청을 대기 시키거나 로깅하며 되돌릴 수 있는 연산을 지원
  • 어떻게 요청을 처리하는 객체와 요청을 연결할 것 인가에 중점을 둠

다른 이름 :

  • 작동(Action), 트랜잭션(Transaction)

참여자 :

  • Command - 연산 수행에 필요한 인터페이스 선언
  • ConcreteCommand - Receiver객체와 액션 간의 연결성 정의
    처리 객체에 정의된 연산을 호출하도록 Execute() 구현
  • Client - ConcreteCommand 객체를 생성하고 처리 객체로 정의
  • Receiver - ConcreteCommand의 기능을 실행하기 위해 사용하는 수신자
  • Invoker(Caller) - 명령어에 처리 수행을 요청

예제 :

package command;

public interface Command {
	
	public abstract void execute();

}
package command;

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();
	}

}
package command;

public class Lamp {

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

package command;

public class LampOnCommand implements Command{
	
	private Lamp theLamp;
	
	public LampOnCommand(Lamp theLamp) {
		this.theLamp = theLamp;
	}
	
	public void execute() {
		theLamp.turnOn();
	}

}
package command;

public class Alarm {

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

package command;

public class AlarmStartCommand implements Command {

	private Alarm theAlarm;
	
	public AlarmStartCommand(Alarm theAlarm) {
		this.theAlarm = theAlarm;
	}
	
	public void execute() {
		theAlarm.start();
	}
}
package command;

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);
		button1.pressed();
		
		Button button2 = new Button(alarmStartCommand);
		button2.pressed();
		button2.setCommand(lampOnCommand);
		button2.pressed();
	}

}
Lamp on
Alarming
Lamp on

동기 :

  • 요청받은 연산이 무엇이며 이를 처리할 객체가 누구인지에 대한 아무 정보없이 임의의 객체에 메시지 보내야 하는 경우
  • 연산을 실행하는 데 필요한 인터페이스를 선언해 놓는 Command 추상 클래스가 핵심
  • 연산을 호출하는 객체와 이를 수행하는 객체를 분리하여 많은 융통성을 부여
  • 각각의 인터페이스 요소가 Command를 상속하는 동일한 서브클래스를 공유함으로써 동일하게 처리됨
  • 명령어를 동적으로 교체 가능하여 상황마다 다르게 기능을 구현해야 할 때 적합

활용성 :

  • 명령 패턴은 콜백을 객체지향 방식으로 나타낸 것 (메서드 호출을 실체화 한 것 = 함수 호출을 객체로 감싼 것)
  • Command의 Execute() 연산은 상태를 저장할 수 있기 때문에 Unexecute() 연산을 Command 인터페이스에 추가하면 실행된 명령어를 모두 기록해 두었다가 역으로 탐색하여 수행과 취소를 무한 반복 할 수 있음
  • 시스템이 고장 났을 때 재적용이 가능하도록 변경 과정에 대한 로깅을 지원하고 싶을 때 Load()와 Store() 연산을 정의하여 상태의 변화를 지속적 저장소에 저장해 둘 수 있음 이를 통해 시스템 장애 시 해당 저장소에 저장된 명령어를 읽어 다시 Execute() 연산으로 재실행 가능
  • Command 패턴으로 트랜잭션의 모델링을 할 수 있음 ⇒ Command 클래스는 일관된 인터페이스를 정의하기 때문에 이로써 모든 트랜잭션이 동일한 방식으로 호출됨 ⇒ 새로운 트랜잭션을 만들면 상속으로 Command 클래스를 확장하면 되므로 시스템 확장도 어렵지 않음
profile
안녕하세요. 자바를 좋아하고 디자인 패턴, Refactoring, Clean Code에 관심이 많은 백엔드 개발자입니다.

0개의 댓글