Search

Chapter 11. 템플릿 메서드 패턴

생성일
2025/06/22 12:07
태그

템플릿 메서드 패턴

템플릿 메서드 패턴은 전체적으로는 동일하면서 부분적으로만 다른 구문으로 구성된 메서드에서, 동일한 기능을 상위 클래스에서 정의하고 확장/변화가 필요한 부분만 서브 클래스에서 구현하도록하여 코드 중복을 최소화하는 디자인 패턴이다.
동일한 기능을 구현하는 부분을 템플릿 메서드라고 부르고, 하위 클래스에서 재정의되는 부분적으로 다른 구문을 primitive 혹은 hook 메서드라 부른다.
AbstractClass : 템플릿 메서드를 정의하는 클래스. 공통 알고리즘을 정의
ConcreteClass : 물려받은 primitive 메서드나 hook 메서드를 구현하는 클래스.
템플릿 메서드 패턴의 순차 다이어그램은 위와 같다. AbstractClass에서 정의되어있는 templateMethod를 수행하는 중에 ConcreteClass에 정의되어있는 primitiveOperation들을 호출한다.

여러 브랜드의 모터

엘레베이터의 모터를 모델링하면서 템플릿 메서드 패턴을 작성해보자.
위 설계를 바탕으로 코드를 작성하면 다음과 같다.
public enum DoorStatus { OPEN, CLOSED } public enum MotorStatus { MOVING, STOPPED }
Java
복사
public class Door { private DoorStatus doorStatus; public Door() { this.doorStatus = DoorStatus.CLOSED; } public DoorStatus getDoorStatus() { return doorStatus; } public void close() { doorStatus = DoorStatus.CLOSED; } }
Java
복사
public class HyundaiMotor { private Door door; private MotorStatus motorStatus; public HyundaiMotor(final Door door) { this.door = door; this.motorStatus = MotorStatus.STOPPED; } public MotorStatus getMotorStatus() { return motorStatus; } public void setMotorStatus(final MotorStatus motorStatus) { this.motorStatus = motorStatus; } public void move() { if (motorStatus == MotorStatus.MOVING) { return; } if (door.getDoorStatus() == DoorStatus.CLOSED) { door.close(); } moveHyundaiMotor(); motorStatus = MotorStatus.MOVING; } private void moveHyundaiMotor() { // move motor } }
Java
복사
하지만 위 코드에서 모터를 HyundaiMotor에서 다른 방식으로 구동하는 LGMotor로 바꾼다면,
public class LGMotor { private Door door; private MotorStatus motorStatus; public LGMotor(final Door door) { this.door = door; this.motorStatus = MotorStatus.STOPPED; } public MotorStatus getMotorStatus() { return motorStatus; } public void move() { if (getMotorStatus() == MotorStatus.MOVING) { return; } if (door.getDoorStatus() == DoorStatus.CLOSED) { door.close(); } moveMotor(); setMotorStatus(MotorStatus.MOVING); } private void moveLGMotor() { // move motor } }
Java
복사
이처럼 코드 중복이 발생한다.
위 설계로 바꾸어 공통되는 부분을 추상 클래스로 묶어 코드 중복을 해결할 수 있다.
public abstract class Motor { protected Door door; private MotorStatus motorStatus; public Motor(final Door door) { this.door = door; motorStatus = MotorStatus.STOPPED; } public MotorStatus getMotorStatus() { return motorStatus; } public void setMotorStatus(final MotorStatus motorStatus) { this.motorStatus = motorStatus; } }
Java
복사
public class HyundaiMotor extends Motor { public HyundaiMotor(final Door door) { super(door); } public void move() { if (getMotorStatus() == MotorStatus.MOVING) { return; } if (door.getDoorStatus() == DoorStatus.CLOSED) { door.close(); } moveMotor(); setMotorStatus(MotorStatus.MOVING); } private void moveHyundaiMotor() { // move motor } }
Java
복사
public class LGMotor extends Motor { public LGMotor(final Door door) { super(door); } public void move() { if (getMotorStatus() == MotorStatus.MOVING) { return; } if (door.getDoorStatus() == DoorStatus.CLOSED) { door.close(); } moveLGMotor(); setMotorStatus(MotorStatus.MOVING); } private void moveLGMotor() { // move motor } }
Java
복사
하지만 여전히 코드 중복이 많이 존재하는 것을 볼 수 있다.
public class HyundaiMotor extends Motor { public HyundaiMotor(final Door door) { super(door); } public void move() { if (getMotorStatus() == MotorStatus.MOVING) { return; } if (door.getDoorStatus() == DoorStatus.CLOSED) { door.close(); } moveMotor(); setMotorStatus(MotorStatus.MOVING); } private void moveHyundaiMotor() { // move motor } }
Java
복사
이와 같은 상황에서 템플릿 메서드 패넡을 통해 코드 중복을 해결할 수 있다.
public abstract class Motor { protected Door door; private MotorStatus motorStatus; public Motor(final Door door) { this.door = door; motorStatus = MotorStatus.STOPPED; } public MotorStatus getMotorStatus() { return motorStatus; } public void setMotorStatus(final MotorStatus motorStatus) { this.motorStatus = motorStatus; } public void move() { if (getMotorStatus() == MotorStatus.MOVING) { return; } if (door.getDoorStatus() == DoorStatus.CLOSED) { door.close(); } moveMotor(); setMotorStatus(MotorStatus.MOVING); } protected abstract void moveMotor(); }
Java
복사
이처럼 템플릿 메서드에서 다른 부분만 primitive 메서드(moveMotor)로 추출하고,
public class HyundaiMotor extends Motor { public HyundaiMotor(final Door door) { super(door); } @Override protected void moveMotor() { // move motor } }
Java
복사
public class LGMotor extends Motor { public LGMotor(final Door door) { super(door); } @Override protected void moveMotor() { // move motor } }
Java
복사
이처럼 하위 클래스에서 다른 부분만 직접 구현하는 방식으로 사용하는 것이다.