Notice
Recent Posts
Recent Comments
Link
일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | |||||
3 | 4 | 5 | 6 | 7 | 8 | 9 |
10 | 11 | 12 | 13 | 14 | 15 | 16 |
17 | 18 | 19 | 20 | 21 | 22 | 23 |
24 | 25 | 26 | 27 | 28 | 29 | 30 |
Tags
- aws
- vue.js
- 원격 브랜 삭제
- 자바 ORM 표준 JPA 프로그래밍
- Stream
- findTopBy
- java
- @TransactionalEventListener
- HandlerMethodArgumentResolver
- 친절한 SQL 튜닝
- multipart테스트
- JPA
- 리눅스
- intellij 즐겨찾기
- ksql
- @Transactional Propagation
- Spring Cloud Netflix
- intellij favorites
- javascript case
- git
- IntelliJ
- ksqldb
- Linux
- #docker compose
- intellij 핵심 단축키
- 리팩토링 2판
- CompletableFuture
- 자바 ORM 표준 JPA 프로그래밍 정리
- 마이크로 서비스
- 백명석님
Archives
- Today
- Total
시그마 삽질==six 시그마
템플릿 메서드 패턴 & 팩토리 메서드 패턴 본문
'자바 객체 지향 디자인 패턴' 책을 구입하시길 추천드립니다.
책 구입을 원하시는분은 요기를 클릭하시면 됩니다.
하단의 내용은 제가 예전에 읽었던 내용을 요약 정리한 것입니다.
1. 템플릿 메소드 패턴
동일한 기능을 상위 클래스에서 정의하면서 확장/변화가 필요한 부분만 서브클래스에서 구현하는 패턴
공통기능을 담당하는 추상클래스의 특정메소드에 (공통기능은 덤) 추상 메소드를 호출하는 코드를 넣어(hook,primitive메서드) 변화가 필요한 부분을 서브클래스에서 구현할 수 있게 해놓은것
하단과 같이 오티스 엘리베이터의 모터 클래스가 있다고 하자
public class OtisMotor {
private Door door ;
private MotorStatus motorStatus ;
public OtisMotor(Door door) {
this.door = door ;
motorStatus = MotorStatus.STOPPED ;
}
private void moveOtisMotor(Direction direction) {
}
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() ;
moveOtisMotor(direction) ;
setMotorStatus(MotorStatus.MOVING) ;
}
}
public 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.OPENED ;
}
}
public enum DoorStatus { CLOSED, OPENED }
public enum Direction { UP, DOWN }
public enum MotorStatus { MOVING, STOPPED}
public class Client {
public static void main(String[] args) {
Door door = new Door() ;
OtisMotor otisMotor = new OtisMotor(door) ;
otisMotor.move(Direction.UP) ;
}
}
만약 요기서 삼성 모터가 추가가 된다면 하단과 같이 삼성모터 클래스를 만든다.
public class SamsungMotor {
private Door door ;
private MotorStatus motorStatus ;
public SamsungMotor(Door door) {
this.door = door ;
motorStatus = MotorStatus.STOPPED ;
}
private void moveSamsungMotor(Direction direction) {
}
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() ;
moveSamsungMotor(direction) ;
setMotorStatus(MotorStatus.MOVING) ;
}
}
public class Client {
public static void main(String[] args) {
Door door = new Door() ;
SamsungMotor samsungMotor = new SamsungMotor(door) ;
samsungMotor.move(Direction.UP) ;
}
}
그런데 오티스 모터와 삼성모터의 코드 중복이 심해진다
그래서 모터 추상클래스를 만들고 공통된 부분을 넣는다
public abstract class Motor {
protected Door door ;
private MotorStatus motorStatus ;
public Motor(Door door) {
this.door = door ;
motorStatus = MotorStatus.STOPPED ;
}
public MotorStatus getMotorStatus() {
return motorStatus;
}
protected void setMotorStatus(MotorStatus motorStatus) {
this.motorStatus = motorStatus;
}
}
public class OtisMotor extends Motor {
public OtisMotor(Door door) {
super(door) ;
}
private void moveOtisMotor(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() ;
moveOtisMotor(direction) ;
setMotorStatus(MotorStatus.MOVING) ;
}
}
public class SamsungMotor extends Motor {
public SamsungMotor(Door door) {
super(door) ;
}
private void moveSamsungMotor(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() ;
moveSamsungMotor(direction) ;
setMotorStatus(MotorStatus.MOVING) ;
}
}
그럼에도 불구하고 move 메소드 내부는 여전히 겹치는 부분이 많다.
이럴때 필요한 것이 템플릿 메소드다.
move 메소드 속에 추상메소드인 hook 메소드를 삽입한다.
public 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 ;
DoorStatus doorStatus = door.getDoorStatus() ;
if ( doorStatus == DoorStatus.OPENED )
door.close() ;
moveMotor(direction) ; //hook, primitive 메소드라한다
setMotorStatus(MotorStatus.MOVING) ;
}
protected abstract void moveMotor(Direction direction) ;
}
public class OtisMotor extends Motor {
public OtisMotor(Door door) {
super(door) ;
}
protected void moveMotor(Direction direction) {
// OtisMotor Motor내부 구현
}
}
public class SamsungMotor extends Motor {
public SamsungMotor(Door door) {
super(door) ;
}
protected void moveMotor(Direction direction) {
// LG Motor내부 구현
}
}
실무에서 사용하는 예시...
@Service
public class AaaServiceImpl extends GenericServiceImpl<A, Long> implements AaaService {
@Resource
private AaaRepository aaaRepository;
@Override
public GenericRepository<A, Long> initializingRepository() {
return aaaRepository;
}
.....
public abstract class GenericServiceImpl<T, PK extends Serializable> implements GenericService<T, PK> {
private GenericRepository<T, PK> domainRepository;
public GenericServiceImpl() {
}
public GenericRepository<T, PK> getDomainRepository() {
if (this.domainRepository == null) {
this.domainRepository = this.initializingRepository();
}
return this.domainRepository;
}
public abstract GenericRepository<T, PK> initializingRepository();
@Transactional
public T add(T entity) {
return this.getDomainRepository().insert(entity);
}
@Transactional
public T edit(T entity) {
return this.getDomainRepository().update(entity);
}
@Transactional
public void remove(PK id) {
this.getDomainRepository().delete(id);
}
@Transactional(readOnly = true)
public T findById(PK id) {
return this.getDomainRepository().selectById(id);
}
2. 팩토리 메소드 패턴
객체를 생성하는 인터페이스는 미리 정의하고 서브클래스에 인스턴스 결정 및 책임을 위임
인스턴스를 생성하는 공장을 템플릿 메서드 패턴으로 만든것이 팩토리 메서드 패턴임
'프로그래밍 > 디자인패턴' 카테고리의 다른 글
데코레이터 패턴(Decorator pattern) (0) | 2020.04.24 |
---|---|
스테이트 패턴(State pattern) (0) | 2020.04.24 |
전략 패턴(Strategy Pattern) (0) | 2020.04.24 |
싱글톤 패턴(Singleton Pattern) (0) | 2020.04.23 |
빌더 패턴(Builder pattern) (0) | 2020.04.23 |
Comments