(인프런) 코딩으로 학습하는 GoF의 디자인 패턴 - 백기선, 강의를 보고 정리한 글입니다.
코드는 GitHub 에 있습니다
#1. 객체 생성 관련 패턴 |
#2. 구조 관련 패턴 |
#3. 행동 관련 패턴 |
||
✔️ 템플릿 메소드 패턴(Template Method Pattern)
알고리즘의 구조를 서브 클래스가 확장할 수 있도록 템플릿으로 제공하여 구체적인 방법을 서브클래스에게 위임하는 패턴입니다.
- 추상클래스는 템플릿을 제공하고 하위 클래스는 구체적인 알고리즘을 제공합니다.
- 전체적인 로직 (큰 틀)은 상위 클래스에 정의되어있지만 → 세부적인 구현은 하위 클래스에 맡겨져 있는 구조입니다.
- 👏🏻 즉, 상위 클래스에서 처리의 흐름을 제어하고, 하위클래스에서 처리의 내용을 구체화하는 디자인 패턴입니다.
→ 추상클래스의 상속을 사용
✔️ 템플릿 메소드 패턴 예시
- 하나의 파일을 읽어와, 사칙연산을 수행하는 코드를 예시로 들겠습니다.
템플릿 메소드 패턴 적용 전
먼저 더하기를 구현한 코드 입니다.
Client
- 클라이언트에서 파일을 읽고, 더하기 연산을 수행하는 process 메소드를 실행시켜 결과를 얻습니다.
public class Client {
public static void main(String[] args) {
FileProcessor fileProcessor = new FileProcessor("number.txt");
int result = fileProcessor.process();
System.out.println(result);
}
}
FileProcessor
- txt 파일이 있다고 가정하고, 파일안의 숫자를 하나씩 불러와 + 기를 연산하고 있습니다.
public class FileProcessor {
private String path;
public FileProcessor(String path) {
this.path = path;
}
public int process() {
try (BufferedReader reader = new BufferedReader(new FileReader(path))) {
int result = 0;
String line = null;
while ((line = reader.readLine()) != null) {
result += Integer.parseInt(line);
}
return result;
} catch (IOException e) {
throw new IllegalArgumentException(path + "에 해당하는 파일이 없습니다.", e);
}
}
}
→ 이것에 대한 문제점은, 만약 -, x, % 등의 연산이 해당 클래스에 추가된다고 하였을 때 파일을 불러오고 읽어들이는 부분이 중복되고 맙니다.
이러한, 정해진 틀 혹은 흐름을 고정적인 템플릿으로 두고, 변경되는 알고리즘(사칙연산) 의 구현만을 하위 클래스에 맡겨버리는게 템플릿 메소드 패턴입니다.
👇
템플릿 메소드 패턴 적용 후
사칙연산의 부분을 추상 메소드로 추출합니다.
FileProcessor
- 흐름은 동일하고, 사칙연산의 부분만 abstract 메소드로 추출하였습니다.
public abstract class FileProcessor {
private String path;
FileProcessor(String path) {
this.path = path;
}
public int process() {
try (BufferedReader reader = new BufferedReader(new FileReader(path))) {
int result = 0;
String line = null;
while ((line = reader.readLine()) != null) {
result = getResult(result, Integer.parseInt(line));
}
return result;
} catch (IOException e) {
throw new IllegalArgumentException(path + "에 해당하는 파일이 없습니다.", e);
}
}
protected abstract int getResult(int result, int line);
}
하위 클래스
- 구체적인 구현을 하위클래스로 확장해 나갑니다.
//----- Plus --------
public class Plus extends FileProcessor {
public Plus(String path) {
super(path);
}
@Override
protected int getResult(int result, int line) {
return result += line;
}
}
//----- Minus --------
public class Minus extends FileProcessor {
public Minus(String path) {
super(path);
}
@Override
protected int getResult(int result, int line) {
return result -= line;
}
}
Client
- 클라이언트에서는 원하는 기능을 구현한 하위클래스를 호출하여 결과값을 얻습니다.
public class Client {
public static void main(String[] args) {
FileProcessor fileProcessor_plus = new Plus("number.txt");
int plus_result = fileProcessor_plus.process();
System.out.println(plus_result);
FileProcessor fileProcessor_minus = new Minus("number.txt");
int minus_result = fileProcessor_minus.process();
System.out.println(minus_result);
}
}
✔️ 템플릿 메소드 패턴 장점, 단점
• 장점
- 템플릿 코드를 재사용하고 중복코드를 줄일 수 있다.
- 템플릿 코드를 변경하지 않고 상속을 받아서 구체적인 알고리즘만 변경할 수 있다.
• 단점
- 리스크프 치환 원칙을 위반할 수도 있다.
- 리스코프 치환원칙이란 - 리스코프 치환 원칙의 핵심은 부모 클래스의 행동 규약을 자식 클래스가 위반하면 안 된다는 것입니다.
- 상속을 받은순간 하위클래스가 템플릿을 정의한 메소드를 잘못 오버라이딩하여 부모의 규약을 위반할 가능성이 있다는 것입니다.
- 알고리즘 구조가 복잡할 수록 템플릿을 유지하기 어려워진다.
'Java > Design Pattern' 카테고리의 다른 글
[디자인 패턴] 행동 패턴 - 방문자 패턴(Visitor Pattern) (0) | 2023.05.05 |
---|---|
[디자인 패턴] 행동 패턴 - 전략 패턴 (Strategy Pattern) (0) | 2023.04.21 |
[디자인 패턴] 행동 패턴 - 상태 패턴 (State Pattern) (0) | 2023.04.19 |
[디자인 패턴] 행동 패턴 - 옵저버(관찰자) 패턴 (Observer Pattern) (0) | 2023.04.13 |
[디자인 패턴] 행동 패턴 - 메멘토 패턴 (Memento Pattern) (0) | 2023.04.12 |