Notice
Recent Posts
Recent Comments
Link
S E P H ' S
[행동 패턴] 커맨드(Command) 패턴 본문
커맨드(Command) 패턴
커맨드 패턴이란?
실행된 기능을 캡슐화함으로써 주어진 여러 기능을 실행할 수 있는 재사용성이 높은 클래스를 설계하는 패턴이다. A 객체에서 B 객체의 메소드를 실행하려면 B를 참조하고 있어야 하는 의존성이 발생하는데 커맨드 패턴을 통해 의존성을 제거할 수 있다.
언제 사용할까?
- 하나의 객체를 통해 여러 객체들에게 명령해야할 때 사용된다.
- 여러 커맨드를 조합하여 하나의 커맨드처럼 사용할 필요가 있을 때 유용
- 이벤트가 발생했을 때, 실행될 기능이 다양하면서도 변경이 필요한 경우에 사용된다.
- 커맨드 발생 시점을 사용자가 커스터마이징 해야할 때 사용된다.
- 커맨드 실행 취소, 재실행 등의 기능을 구현해야 할 때
구조
- Command : 실행될 기능에 대한 인터페이스. 실행될 기능을 executer 메소드로 선언한다.
- ConcreteCommand : 실제로 실행되는 기능을 구현. Command 인터페이스를 구현한다.
- Invoker : 기능의 실행을 요청하는 호출자 클래스
- Receiver : ConcreteCommand에서 execute 메소드를 구현할 때 필요한 클래스. ConcreteCommand의 기능을 실행하기 위해 사용하는 수신자 클래스
장단점
장점
- 작업을 수행하는 객체와 요청하는 객체를 분리하기 때문에 SRP 원칙을 준수한다.
- 기존 코드 수정 없이 새로운 리시버와 새로운 커맨드 추가가 가능하기 때문에 OCP 원칙을 준수한다.
- 커맨드 단위의 별도 액션이 가능하고 커맨드 상속 및 조합을 통해 더 정교한 커맨드 구현이 가능하다.
- 인보커, 리시버, 커맨드가 각각 캡슐화 되어 결합도가 낮아진다.
단점
- 리시버 객체의 동작이 늘어날 때마다 커맨드 클래스가 늘어나는 단점이 있다.
예시
버튼을 사용하여 컴퓨터 전원을 켜고 끄는 것을 예시로 들어볼 것이다. 명령은 turnOn, turnOff의 두 가지이고 이 두가지 명령 클래스(ConcreteCommand)는 Command 인터페이스를 구현한 구현체이다. 이 명령을 받는 리시버는 컴퓨터이고 명령에 따라 상태가 변화하게 된다. 그리고 명령을 호출하는 인보커 역할은 버튼이 한다.
public interface Command {
public void execute();
}
public class ComputerOnCommand implements Command {
private Computer computer;
public ComputerOnCommand(Computer computer) {
this.computer = computer;
}
@Override
public void execute() {
computer.turnOn();
}
}
public class ComputerOffCommand implements Command {
private Computer computer;
public ComputerOffCommand(Computer computer) {
this.computer = computer;
}
@Override
public void execute() {
computer.turnOff();
}
}
public class Computer {
public void Computer() {}
public void turnOn() {
System.out.println("컴퓨터 전원 켜짐");
}
public void turnOff() {
System.out.println("컴퓨터 전원 꺼짐");
}
}
커맨드 인터페이스를 구현한 turnOn, turnOff 커맨드 객체, 커맨드를 수행하는 리시버 객체인 Computer를 구현했으니 커맨드 객체를 사용할 Invoker, 버튼 클래스를 구현한다.
public class Button {
private Command command;
public Button(Command command) {
this.command = command;
}
public void setCommand(Command command) {
this.command = command;
}
public void pressedButton() {
this.command.execute();
}
}
setCommand는 커맨드를 변경하는 메소드이고 pressedButton은 command를 실행시키는 역할을 한다.
테스트
public class CommandTest {
public static void main(String[] args) {
Computer computer = new Computer();
ComputerOnCommand onCmd = new ComputerOnCommand(computer);
ComputerOffCommand offCmd = new ComputerOffCommand(computer);
// 버튼을 생성할 때 커맨드 상태를 통해 생성함
Button btn = new Button(onCmd);
btn.pressedButton();
btn.setCommand(offCmd);
btn.pressedButton();
}
}
정리
- 하나의 객체를 통해 여러 객체들에게 명령해야할 때 사용하며 결합도를 낮출 수 있지만 리시버 객체의 동작이 늘어나게 되면 클래스가 많아지는 단점을 갖고 있다.
- 커맨드 패턴은 전략 패턴과도 많이 비교가 된다.
- 커맨드 패턴은 무엇을에 초점을 둔다. 어떻게 할지에 대한 방법은 외부에서 정의되고 주입을 해주며 그 방법을 실행하는 것이 중요하다.
- 전략패턴은 어떻게에 초점을 둔다. 하고자 하는 것은 정해졌지만 방법은 상황에 따라 정해야 하는, 유연성을 고려하며 구현하는 것이 중요하다. 인터페이스의 메소드에 직접적으로 의존을 하여 해당 메소드의 파라미터들에 강하게 영향을 받는다.
- 커맨드 vs 전략 에 대해서는 추후에 더 자세히 다뤄보도록 할 것이다.
'Programing & Coding > Design Pattern' 카테고리의 다른 글
[행동 패턴] 인터프리터(Interpreter) 패턴 (0) | 2023.03.26 |
---|---|
[구조 패턴] 데코레이터(Decorator) 패턴 (0) | 2023.03.26 |
[행동 패턴] 방문자(Visitor) 패턴 (0) | 2023.03.19 |
[행동 패턴] 템플릿 메소드(Template Method) 패턴 (0) | 2023.03.19 |
[행동 패턴] 상태(State) 패턴 (0) | 2023.03.19 |