2023.08.25

커맨드 패턴

커맨드 패턴이란, 요청을 객체의 형태로 캡슐화 해서 사용자가 보낸 요청을 나중에 이용하도록 하는 패턴이다. 호출과 수신자 클래스 사이의 의존성이 제거 되며, 이벤트가 발생했을 때 실행될 기능이 다양하지만, 변경이 필요한 경우 재사용 할 수 있어 유용하다.


구현

리모콘은 실행활에서 자주 사용한다. 해당 버튼이 눌렸다는 이벤트가 있지만, 각각 하는 역할이 다르다.

public interface Command {
	public void run();
}

커맨드를 실행시킨다는 인터페이스가 있다.

public class VolumeUpCommand implements Command {
	private Speaker speaker;

	public VolumeUpCommand(Speaker speaker) {
		this.speaker = speaker;
	}

	@Override
	public void run() {
		speaker.volumeUp();
	}
}

public class VolumeDownCommand implements Command {
	private Speaker speaker;

	public VolumeDownCommand(Speaker speaker) {
		this.speaker = speaker;
	}

	@Override
	public void run() {
		speaker.volumeDown();
	}
}

public class Speaker {
	public void volumeUp() {
		System.out.println("볼륨이 증가했다.");
	}

	public void volumeDown() {
		System.out.println("볼륨이 감소했다.");
	}
}


볼륨을 증가시키거나 볼륨을 감소하도록 명령할 수 있기 때문에 Command 를 구현한 증가 커맨드와 감소 커맨드가 있고, 실질적으로 메소드는 스피커 클래스에 구현한다. 이제 리모콘에 버튼이 눌렸을 때 커맨드를 수행하도록 구성하자.


public class RemoteControl {
	private Command command;

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

	public void pressButton() {
		command.run();
	}
}


실제로 리모콘 조작을 한다고 가정하면…


public class Client {
	public static void main(String[] args) {
		Speaker speaker = new Speaker();

		Command volumeUpCommand = new VolumeUpCommand(speaker);
		Command volumeDownCommand = new VolumeDownCommand(speaker);

		RemoteControl remoteControl = new RemoteControl();
		
		remoteControl.setCommand(volumeUpCommand);
		remoteControl.pressButton();

		remoteControl.setCommand(volumeDownCommand);
		remoteControl.pressButton();
	}

}

여기서 setCommand → pressButton 과정이 반복되기 때문에 별도로 묶어두는 메소드 등을 추가할 수 있을 것 같다.


그냥 if 나 switch-case 로 구현한 것과 다른점?

조건 분기와 다른 점은 새로운 기능을 추가할 때 분기에 하나씩 추가해야하지만, 커맨드 패턴의 경우 새로운 클래스만 추가하면 되기 때문에 OCP에 위배되지 않는다. 또한, 캡슐화를 통해서 실제 해당 커맨드를 호출하는 부분에서는 세부 내용을 모르더라도 작동한다는 장점이 있다.



Leave a comment