6. Command Pattern

최정훈·2024년 11월 11일

1. 작업을 요청하는 것과 처리하는 것의 분리


만능 리모컨을 만든다고 가정하자. 여러 개의 버튼을 통해서 여러 기기들을 다룰 수 있는 리모컨이다. 하지만, 다양한 기기들은 서로 다른 기능들을 가지고 있기 때문에, 기기들이 공통적으로 가지는 기능을 인터페이스 화 시키는 것은 불가능에 가깝다. 그렇다고, 리모컨의 버튼마다 특정한 기능을 지정해버리면, OCP를 위배할 것이다.

이와 같은 문제는 Command Pattern을 이용해서 커맨드 객체를 추가하고, 작업을 요청하는 것과 작업을 처리하는 것을 분리함으로써 해결할 수 있다.

2. Command Pattern


요청을 객체로 캡슐화해서 객체를 서로 다른 요청에 따라 매개변수화할 수 있다. 또한, 요청을 큐에 저장하거나 로그로 기록하거나 작업 취소 또한 가능하다.

커맨드 객체는 일련의 행동을 특정한 리시버와 연결해서 행동을 캡슐화한다. 외부에서 보면 어떤 객체가 무슨 일을 하는지 알 수 없다. 그저, 매서드를 호출하면 해당 요청이 처리된다는 사실만 알 수 있다.

주로 다음과 같은 4가지의 요소로 이루어져 있다.

  • Command - excute()매서드를 선언하여 Receiver의 수행을 구체화한다.
  • Concrete Command - Command 인터페이스를 구체화하고, 이를 통해 Receiver클래스의 함수를 호출한다.
  • Invoker - 사용자의 요청을 Command객체로 변환하며, 이 객체를 실행한다.
  • Receiver - 요청을 수행하는데 필요한 실제 작업을 구현한 클래스이다.

Command Pattern을 적용한 만능 리모컨의 코드는 다음과 같다.

//Command
public interface Command{
	public void execute();
	public void undo();
}

이는 Command클래스이다. 리모컨의 버튼이 눌렸을 때, 어떤 버튼이 눌렸는지에 따른, 해야할 일들을 담고있다.

예를 들어서 조명을 켤 때 필요한 커맨드와 간단한 리모컨을 구현해보자.

//Concrete Command
public class LightOnCommand implements Command{
	Light light;
	
	public LightOnCommand(Light light){ //어떤 특정한 조명을 켤건지. ex) 거실조명 등
		this.light = light;
	}
	
	public void execute(){ //light객체에 있는 on()을 호출함
		light.on();
	}
	
	public void undo(){
		light.off();
	}
}

// Invoker
public class SimpleRemoteControl{
	Command slot; //Command를 저장할 슬롯
	public SimpleRemoteControl() {}
	
	public void SetCommand(Command command){
		slot = command;
	}
	
	public void buttonWasPressed(){ //버튼을 누르면 발동되는 메서드. 슬롯에 연결된 커맨드 객체의 execute()만 호출한다.
		slot.execute();
	}
}

// Receiver는 Light이다

이제, 리모컨을 사용해서 불을 켜기 위해서는, SetCommand() 매서드를 통해서 LightOnCommand 객체를 리모컨 객체의 slot에 지정하고, 리모컨의 버튼을 누르면 된다.

profile
게임개발자(희망)의 공부일지

0개의 댓글