하위 클래스에서 구체적으로 처리하는 디자인패턴
템플릿 메소드 패턴에서는 부모의 자식 간의 의존성 방향을 부모가 자식을 아는 방향으로 역전시키게 된다.
일반적으로는 자식이 부모의 세부구현을 알고서 이를 이용하는 쪽으로 상속이 일어나지만, 템플릿 메서드 패턴에서는 부모가 반대로 추상 메소드 인터페이스를 통해서 자식을 알게 된다.
Context(공통된 부분)과 Strategy(변경되는 부분)을 분리하여 Strategy 캡슐화를 통해 Context 변경없이 유연하게 기능을 확장하고 수정할 수 있는 디자인 패턴
커맨드패턴은 객체의 행위(메서드)를 클래스로 만들어 캡슐화하는 패턴이다.
어떤 객체(A)에서 다른 객체(B)의 메서드를 실행하려면 객체(B)를 참조하고 있어야 하는 의존성이 발생한다. 이와 같은 상황에서 커맨드패턴을 적용하면 의존성을 제거할 수 있다. 또한 기능이 수정되거나 변경이 일어날 때 A클래스의 코드를 수정없이 기능에 대한 클래스를 정의하면 되므로 시스템이 확장성이 있으면서 유연성을 가질 수 있다.
import java.util.HashMap;
import java.util.Map;
// Command Interface
interface Command {
void execute();
}
// Concrete Command Classes
class LightOnCommand implements Command {
private Light light;
public LightOnCommand(Light light) {
this.light = light;
}
public void execute() {
light.switchOn();
}
}
class LightOffCommand implements Command {
private Light light;
public LightOffCommand(Light light) {
this.light = light;
}
public void execute() {
light.switchOff();
}
}
// Receiver Class
class Light {
public void switchOn() {
System.out.println("Light is switched on");
}
public void switchOff() {
System.out.println("Light is switched off");
}
}
// Invoker Class
class RemoteControl {
private Map<String, Command> commands = new HashMap<>();
public void register(String commandName, Command command) {
commands.put(commandName, command);
}
public void execute(String commandName) {
Command command = commands.get(commandName);
if (command != null) {
command.execute();
} else {
System.out.println("Invalid command");
}
}
}
// Client Class
public class Main {
public static void main(String[] args) {
RemoteControl remoteControl = new RemoteControl();
Light light = new Light();
Command lightOnCommand = new LightOnCommand(light);
Command lightOffCommand = new LightOffCommand(light);
remoteControl.register("on", lightOnCommand);
remoteControl.register("off", lightOffCommand);
remoteControl.execute("on");
remoteControl.execute("off");
}
}
객체 내부 상태에 맞춰 스스로 행동을 변경하는 패턴
동일한 메서드가 상태에 따라 다르게 동작할 때 사용할 수 있는 패턴이다.
// 상태 인터페이스
public interface State {
public void doAction(Context context);
}
// 상태 구현체 1
public class StateA implements State {
public void doAction(Context context) {
System.out.println("State A");
context.setState(new StateB());
}
}
// 상태 구현체 2
public class StateB implements State {
public void doAction(Context context) {
System.out.println("State B");
context.setState(new StateA());
}
}
// 컨텍스트 클래스
public class Context {
private State state;
public Context() {
state = new StateA();
}
public void setState(State state) {
this.state = state;
}
public void doAction() {
state.doAction(this);
}
}
// 테스트 클래스
public class StatePatternTest {
public static void main(String[] args) {
Context context = new Context();
context.doAction(); // 출력: State A
context.doAction(); // 출력: State B
context.doAction(); // 출력: State A
}
}
전략 패턴의 경우, 인터페이스가 완충역할을 하는 반면에, 템플릿메서드 패턴의 경우에는 의존성 뱡향을 변경합니다.
중간에 인터페이스가 있기 때문에, 변화가 많이 일어날 경우 도움이 될 수 있다.
전략 패턴은 '어떻게' 동작을 수행하냐에 중점을 두고,
커맨드 패턴은 '무엇을' 동작하냐에 중점을 둡니다.
전략 패턴은 상속을 대체 할 수 있다.
상태 패턴은 코드 내 조건 문을 대체 할 수 있다.