-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat: Add the template method and callback pattern
- Loading branch information
Showing
3 changed files
with
160 additions
and
0 deletions.
There are no files selected for viewing
160 changes: 160 additions & 0 deletions
160
docs/design-pattern/03-behavior-pattern/09-template-method-pattern.md
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,160 @@ | ||
--- | ||
title: Template Method Pattern | ||
description: Understand about state pattern | ||
tags: [design-pattern, behavior-pattern] | ||
keywords: [design pattern, template method pattern] | ||
last_update: | ||
date: 2024-03-15 | ||
--- | ||
|
||
import Tabs from '@theme/Tabs'; | ||
import TabItem from '@theme/TabItem'; | ||
|
||
## Overview | ||
Abstract Class 는 템플릿 메소드를 제공하고 <br></br> | ||
하위 클래스는 구체적인 행위를 정의한다. | ||
|
||
![Template_Method_Overview](screenshots/template_method_pattern.png) | ||
|
||
## Why to use | ||
코드를 재사용하고 구체적인 행위만 분리할 수 있다. | ||
|
||
## When to use | ||
공통된 로직을 그대로 두고 차이가 존재하는 메소드만 분리하여 SRP / OCP 를 지키고자 할 때. | ||
|
||
|
||
## Pros and Cons | ||
### Pros | ||
- 템플릿 코드 재사용 <br></br> | ||
코드 중복 제거 | ||
- SRP / OCP 준수 | ||
|
||
### Cons | ||
- 리스코프 치환 원칙 위배 위험 <br></br> | ||
인터페이스 시그니처만 지키고, 실제 동작은 원래 의도와 다르게 이뤄질 수 있다. | ||
- 템플릿을 제외한 메소드가 많아질 수록 템플릿 메소드가 복잡해질 수 있다. | ||
|
||
> 추상 클래스 템플릿 메소드에 `final` 키워드를 사용하여 Override 를 방지하라. | ||
## Example | ||
|
||
<Tabs> | ||
<TabItem value="abstract" label="AbstractFileProcessor.java"> | ||
|
||
```java | ||
abstract class AbstractFileProcessor { | ||
final public int process(String filePath) throws FileNotFoundException { | ||
try (BufferedReader br = new BufferedReader(new FileReader(filePath))) { | ||
|
||
OptionalInt result = br.lines() | ||
.mapToInt(Integer::parseInt) | ||
.reduce(this::calculate); | ||
|
||
if (result.isEmpty()) throw new IllegalStateException("The file has no content"); | ||
return result.getAsInt(); | ||
|
||
} catch (IOException e) { | ||
throw new FileNotFoundException(e.getMessage()); | ||
} | ||
} | ||
|
||
abstract protected int calculate(int prevValue, int nextValue); | ||
} | ||
|
||
``` | ||
|
||
</TabItem> | ||
<TabItem value="PlusFileProcessor" label="PlusFileProcessor.java"> | ||
|
||
```java | ||
class PlusFileProcessor extends AbstractFileProcessor { | ||
@Override | ||
protected int calculate(int prevValue, int nextValue) { | ||
return prevValue + nextValue; | ||
} | ||
} | ||
|
||
``` | ||
|
||
</TabItem> | ||
<TabItem value="MultiplyFileProcessor" label="MultiplyFileProcessor.java"> | ||
|
||
```java | ||
class MultiplyFileProcessor extends AbstractFileProcessor { | ||
@Override | ||
protected int calculate(int prevValue, int nextValue) { | ||
return prevValue * nextValue; | ||
} | ||
} | ||
``` | ||
|
||
</TabItem> | ||
</Tabs> | ||
|
||
# Template Callback Pattern | ||
|
||
## Example (2) | ||
|
||
<Tabs> | ||
<TabItem value="Operation" label="Operation.java"> | ||
|
||
```java | ||
public interface Operation<T> { | ||
T operate(T accumulator, T currentValue); | ||
}] | ||
``` | ||
</TabItem> | ||
|
||
<TabItem value="templateInterface" label="FileProcessor.java"> | ||
|
||
```java | ||
interface FileProcessor<T> { | ||
T process(String filePath, Operation<T> operation) throws FileNotFoundException; | ||
} | ||
|
||
``` | ||
</TabItem> | ||
<TabItem value="SingletonOperation" label="SingletonIntOperation.java"> | ||
|
||
```java | ||
@RequiredArgsConstructor | ||
enum SingletonIntOperation implements Operation<Integer> { | ||
PLUS((accumulator, currentValue)-> accumulator + currentValue), | ||
MULTIPLY((accumulator, currentValue)-> accumulator * currentValue); | ||
|
||
private final BiFunction<Integer, Integer, Integer> operation; | ||
|
||
@Override | ||
public Integer operate(Integer accumulator, Integer currentValue) { | ||
return this.operation.apply(accumulator, currentValue); | ||
} | ||
} | ||
|
||
``` | ||
|
||
</TabItem> | ||
<TabItem value="IntegerFileProcessor" label="IntegerFileProcessor.java"> | ||
|
||
```java | ||
public class IntegerFileProcessor implements FileProcessor<Integer> { | ||
@Override | ||
public Integer process(String filePath, Operation<Integer> operation) throws FileNotFoundException { | ||
try (BufferedReader br = new BufferedReader(new FileReader(filePath))) { | ||
|
||
OptionalInt result = br.lines() | ||
.mapToInt(Integer::parseInt) | ||
.reduce(operation::operate); | ||
|
||
if (result.isEmpty()) throw new IllegalStateException("The file has no content"); | ||
return result.getAsInt(); | ||
|
||
} catch (IOException e) { | ||
throw new FileNotFoundException(e.getMessage()); | ||
} | ||
} | ||
} | ||
|
||
``` | ||
|
||
</TabItem> | ||
</Tabs> |
Binary file added
BIN
+168 KB
docs/design-pattern/03-behavior-pattern/screenshots/template_callback_pattern.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added
BIN
+122 KB
docs/design-pattern/03-behavior-pattern/screenshots/template_method_pattern.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.