디자인패턴_Template Pattern of Behavioral Pattern
2021. 1. 15. 11:20ㆍ2021/JOB DA STUDY
템플릿 메서드 패턴 이란,
어떤 작업을 처리하는 일부분을 서브 클래스로 캡슐화해 전체 일을 수행하는 구조는 바꾸지 않으면서 특정 단계에서 수행하는 내역을 바꾸는 패턴이다.
- 전체적으로 동일하면서 부분적으로는 다른 구문으로 구성된 메서드의 코드 중복을 최소화할 때 유용
- 동일한 기능은 상위 클래스에서 정의하면서, 확장/변화가 필요한 부분만 서브 클래스에서 구현할 수 있도록 한다.
- AbstractClass
-템플릿 메서드를 정의하는 클래스
-하위 클래스에 공통 알고리즘을 정의하고, 하위 클래스에서 구현될 기능을 primitiveMethod 또는 hookMethod로 정의 하는 클래스
- ConcreteClass
-물려받은 Primitive 메서드 또는 hook 메서드를 구현하는 클래스
-상위 클래스에서 구현된 템플릿 메서드의 일반적인 알고리즘을 하위 클래스에서 적합하게 primitive 메서드나 hook메서드를 오버라이드하는 클래스
여러 회사의 모터 지원하기
엘리베이터 제어 시스템에서 모터 구동시키는 기능
HyundaiMotor Class <------- move()메서드를 실행시 안전을 위해 Door가 닫혀 있는지 확인 -------> Door Class
Enumeration Interface
- MotorStatus: Moving, Stopped
- DoorStatus: Opened, Closed
- MotorStatus: UP, DOWN
public enum DoorStatus { CLOSED, OPENED }
public enum MotorStatus { MOVING, STOPPED }
public class Door{
private DoorStatus doorStatus;
//문의 Default Value는 CLOSED
public Door() { doorStatus = DoorStatus.CLOSED; }
//문의 상태 반환
public DoorStatus getDoorStatus() { return doorStatus; }
public void close() { doorStatus = DoorStatus.CLOSED; }
public void open() { doorStatus = DoorStatus.OPENED; }
public class HyundaiMotor{
private Door door;
private MotorStatus motorStatus;
//엘리베이터 초기 상태 = 멈춤
public HyundaiMotor(){
this.door = door;
motorStatus = motorStatus.STOPED;
}
//엘리베이터 Motor 구동
private void moveHyundaiMotor(Direction direction){
}
//엘리베이터 Motor의 상태 get
public MotorStatus getMotorStatus() { return motorStatus; }
//엘리베이터 Motor의 상태 set
private void setMotorStatus() { this.motorStatus = motorStatus; }
public void move(Direction direction){
//Motor가 이동중이면 아무 작업 하지 않음
MotorStatus motorStatus = getMotorStatus();
if(motorStatus == MotorStatus.MOVING) return;
//Dooe가 열려있으면 닫음
DoorStatus doorStatus = door.getDoorStatus();
if(doorStatus == DoorStatus.OPENED) door.close();
//Hyundai 모터를 주어진 방향으로 이동시킴
moveHyundaiMotor(direction);
//Motor의 상태를 Moving으로 변경
setMotorStatus(MotorStatus.MOVING);
}
}
- HynudaiMotor 클래스의 move 메서드는 getMotorStatus 메서드를 호출해 모터의 상태를 조회 (Motor동작 중인 경우 -> move 메서드 실행 종료)
- Door 클래스의 getDoorStatus 메서드를 호출해 문의 상태 조회 1. DoorStatus.OPENED -> DoorStatus.CLOSED 호출해 문 닫기 2. moveHyundaiMotor 메서드 호출 -> MotorStatus.MOVING 3. setMotorStatus를 호출해 모터의 상태를 MOVING으로 기록
public class Client{
public static void main(String[] args){
Door door = new Door();
HyundaiMotor hyundaiMotor = new HyundaiMotor(door);
hyundaiMotor.move(Direction.UP);
}
}
문제점
*** 다른 회사(LG)의 모터를 제어해야 하는 경우 ***
public class LGMotor{
private Door door;
private MotorStatus motorStatus;
// STOPPED
public LGMotor() {
this.door = door;
motorStatus = MotorStatus.STOPPED;
}
//MOVING
private void moveLGMotor(Direction direction){
}
public MotorStatus getMotorStatus() { return motorStatus; }
private void setMotorStatus() { 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();
moveLGMotor(direction);
setMotorStatus(MotorStatus.MOVING);
}
}
- LGMotor 와 HyundaiMotor는 많은 중복 코드를 가진다.
- 중복코드 -------------> 유지보수성을 악화
해결책
- 2개 이상의 클래스가 유사한 기능을 제공하면서, 중복된 코드가 있는 경우 상속을 이용해 코드 중복의 문제 피할 수 있다.
*** HyundaiMotor 와 LGMotor의 공통적인 기능을 구현하는 클래스 ***
public abstract class Motor {
//Door 객체는 자식 클래스에 따라 변경
protected Door door;
private MotorStatus motorStatus;
public Motor(Door door){
this.door = door;
motorStatus = MotorStatus.STOPPED;
}
public MotorStatus getMotorStatus() {return MotorStatus; }
//protected = setMotorStatus는 자식 클래스에 따라 변경
protected void setMotorStatus(MotorStatus motorStatus) { this.motorStatus = motorStatus; }
}
*** Motor 클래스를 상속받아 HyundaiMotor 클래스 구현 ***
public class HyundaiMotor extends Motor{
//Motor(Door door) 상속: STOPPED
public HyundaiMotor(Door door) { super(door); }
//MOVING
private void moveHyundaiMotor(Direction direction){
}
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);
}
}
*** Motor 클래스를 상속받아 LGMotor 클래스 구현 ***
public class LGMotor extends Motor{
//Motor(Door door) 상속: STOPPED
public LGMotor(Door door) { super(door); }
//MOVING
private void moveLGMotor(Direction direction){
}
public void move(Direction direction){
MotorStatus motorStatus = getMotorStatus();
if(motorStatus == MotorStatus.MOVING) return;
DoorStatus doorStatus = door.getDoorStatus();
if(doorStatus == DoorStatus.OPENED) door.close();
moveLGMotor(direction);
setMotorStatus(MotorStatus.MOVING);
}
}
- Motor 클래스를 상위 클래스로 정의함으로써 중복코드 제거 가능
- move 메서드에는 코드 중복 문제가 존재
- move 메서드와 같이 부분적으로 중복되는 경우, 상속을 활용해 코드 중복을 피할 수 있다.
move Method에서 moveHyundaiMotor 메서드와 moveLGMotor 메서드를 호출하는 부분만 다르다.
moveHyundaiMotor 메서드와 moveLGMotor 메서드는 기능면에서는 동일하다.
↓
1. move 메서드를 상위 Motor 클래스로 이동
2. moveHyundaiMotor 메서드와 moveLGMotor 메서드의 호출 부분을 하위 클래스에서 Override
public abstract class Motor {
********* 동일 *********
public void move(Direction direction){
MotorStatus motorStatus = getMotorStatus();
if(motorStatus motorStatus == MotorStatus.MOVING) return;
DoorStatus doorStatus = door.getDoorStatus();
if(doorStatus == DoorStatus.OPENING) door.close();
//HyundaiMotor 와 LGMotor에서 오버라이드
moveMotor(direction);
setMotorStatus(MotorStatus.MOVING);
}
}
public class HyundaiMotor extends Motor{
public HyundaiMotor(Door door) { super(door); }
//@Override
protected void moveMotor(Direction direction){
}
}
public class LGMotor extends Motor{
public LGMotor(Door door) { super(door); }
//@Override
protected void moveMotor(Direction direction){
}
}
- Motor클래스의 move메서드는 HyundaiMotor 와 LGMotor에서 동일한 기능을 구현하면서, 각 하위 클래스에서 구체적으로 정의할 필요가 있는 부분(moveMotor 메서드)만 각 하위 클래스에서 Override
'2021 > JOB DA STUDY' 카테고리의 다른 글
디자인패턴_Decorator Pattern of Structural Pattern (0) | 2021.01.19 |
---|---|
디자인패턴_Observer Pattern of Behavioral Pattern (0) | 2021.01.15 |
Super (0) | 2021.01.15 |
디자인패턴_Command Pattern of Behavioral Pattern (0) | 2021.01.14 |
Interface (0) | 2021.01.14 |