템플릿 메소드 패턴: 전제적으로 동일하면서 부분적으로 상이한 문장을 가지는 메소드의 코드 중복을 최소화할 때 유용한 패턴
기존 코드: 엘리베이터 제어 시스템에서 모터를 구동시키는 기능이다. HyundaiMotor는 모터를 제어하여 엘리베이터를 이동시키는 클래스이고, Door는 문을 열거나 닫는 기능을 제공하는 클래스이다.
public enum DoorStatus { CLOSED, OPENDED } public enum MotorStatus { MOVING, STOPPED } class Door{ private DoorStatus doorStatus; public Door(){ doorStatus=DoorStatus.CLOSED; } public DoorStatus getDoorStatus(){ return doorStatus; } public void close(){ doorStatus=DoorStatus.CLOSED; } public void open(){ doorStatus=DoorStatus.OPENDED; } } class HyundaiMotor{ private Door door; private MotorStatus motorStatus; public HyundaiMotor(Door door){ this.door=door; motorStatus=MotorStatus.STOPPED; } private void moveHyundaiMotor(Direction direction){ // Hyundai Motor를 구동시킨다. } public MotorStatus getMotorStatus(){ return motorStatus; } private void setMotorStatus(MotorStatus motorStatus){ this.motorStatus=motorStatus; } public void move(Direction direction){ MotorStatus motorStatus=getMotorStatus(); if (motorStatus==MotorStatus.MOVING) return; DoorStatus doorStatus=door.getDoorStatus(); if(doorStatus == DoorStatus.OPENED) door.close(); moveHyundaiMotor(direction); setMotorStatus(MotorStatus.MOVING); } } public class Client{ public static void main(String[] args){ Door door=new Door(); HyundaiMotor hyundaiMotor=new HyundaiMotor(door); hyundaiMotor.move(Direction.UP); } }
이 때, LG에서도 LGMotor클래스를 제작했다고 가정해보자!
HyundaiMotor와 기능이 비슷할 것이기 때문에 Motor라는 추상 클래스를 만들고 LGMotor와 HyundaiMotor가 상속받는 형식으로 제작할 수 있다.
그러나 핵심 기능에 해당하는 move() 메소드를 살펴보니 HyundaiMotor와 LGMotor의 코드가 거의 동일하였다.
따라서 move 메소드에서 공통적인 부분을 상위 클래스인 Motor로 이동하였다.
이렇게 공통 알고리즘이 정의된 메소드를 템플릿 메소드라고 부른다.
Motor의 move는 템플릿 메소드로, Hyundai와 LG의 move 메소드에서 공통적인 부분을 내용으로 지니고 추가로 moveMotor를 호출한다. 이는 공통이 아닌 부분도 존재하기 때문이다.
이 moveMotor는 LG와 Hyundai에서 구현하도록 한다.
이렇게 하위 클래스에서 구현될 메소드를 Primitive Operation이라고 한다.
abstract class Motor{ private Door door; private MotorStatus motorStatus; public Motor(Door door) { this.door=door; motorStatus=MotorStatus.STOPPED; } public MotorStatus getMotorStatus() { return motorStatus; } private void setMotorStatus(MotorStatus motorStatus) { this.motorStatus=motorStatus; } public void move(Direction direction) { MotorStatus motorStatus=getMotorStatus(); if(motorStatus==MotorStatus.MOVING) return; DoorStaus=door.getDoorStatus(); if(doorStatus==DoorStatus.OPENED) door.close(); moveMotor(direction); // 하위 클래스에서 override됨 setMotorStatus(MotorStatus.MOVING); } protected abstract void moveMotor(Direction direction); } class HyundaiMotor extends Motor{ public HyundaiMotor(Door door) { super(door); } protected void moveMotor(Direction direction) { // Hyundai Motor를 구동시킨다. } } class LGMotor extends Motor{ public LGMotor(Door door) { super(door); } protected void moveMotor(Direction direction) { // LG Motor를 구동시킨다. } }