템플릿 패턴은 알고리즘을 나타내는 부분을 추상 클래스로 캡슐화하는 것으로 구성됩니다.
이 추상클래스의 일부 메서드는 정의되지 않은 채로 남아있으며, 서브 클래스는 이 정의되어있지 않은 메서드를 구현하여
알고리즘의 비어있는 부분을 채울 수 있습니다.
import * as fs from 'fs';
abstract class Config {
protected data: Record<string, any>;
public read(file: string) {
this.data = this.deserialize(fs.readFileSync(file, 'utf-8'));
}
protected deserialize(data: string): Record<string, any> {
throw new Error();
}
public get(key: string): any {
return this.data[key];
}
}
class JsonConfig extends Config {
protected deserialize(data: string): Record<string, any> {
return JSON.parse(data);
}
}
class IniConfig extends Config {
protected deserialize(data: string): Record<string, any> {
return ini.parse(data);
}
}
위 예시는 전략 패턴에서 사용했던 예시와 비슷합니다.
추상 클래스로 정의한 Config class 는 deserialize 메서드의 구현 부분이 비어있습니다. 이런 형태로 템플릿을 만들어놓고,
JSON 형식 또는 ini 형식에 대한 deserialize 는 각 클래스에서 구체적인 구현을 제공하는 형태입니다.
전략패턴에서처럼 strategy 를 따로 지정할 필요없이 필요한 기능은 클래스 자체에서 수행됩니다.
위에서 적은 것처럼 이 템플릿 패턴이 전략 패턴과 유사하지만 차이점은 구조와 구현에 있습니다.
두 패턴 다 공통 부분을 재사용하면서 알고리즘의 일부분을 변경할 수 있습니다. 다만 전략 패턴은 동적으로 런타임에 변경할 수 있는 반면
템플릿 패턴은 클래스가 정의되는 순간 알고리즘이 완성됩니다.
이러한 차이점을 알고 더 적절한 패턴을 사용하는 것은 결국 개발자의 몫입니다.
abstract class CommonHandler {
protected originRequest: any;
protected convertedRequest: any;
protected abstract convertRequest(): Promise<any>;
protected async initialize(): Promise<void> {
await this.convertRequest();
}
public async getRequest(): Promise<any> {
await this.initialize();
return this.convertedRequest;
}
...
}
class AHandler extends CommonHandler {
protected async convertRequest(): Promise<any> {
// convert originRequest
}
}
class BHandler extends CommonHandler {
protected async convertRequest(): Promise<any> {
// convert originRequest
}
}
위 코드는 현재 회사에서 템플릿 패턴을 사용하고 있는 부분을 일부 가져와봤는데요.
연동된 곳마다 다른 스펙의 request 를 받고 이를 공통의 convertedRequest 로 변환해야 하는 부분에서, 변환하는 부분의 구현만
다르게 가져가면 되므로 공통의 로직은 CommonHandler 에 모아두고 convertRequest 만 서브 클래스에서 구현하는 형태로 가져가게 되었습니다. 확실히 확장이 필요한 부분만 서브 클래스에서 구현을 가져가면서 다른 부분의 코드 중복을 최소화 할 수 있었죠.
하지만 점점 CommonHandler 를 상속받는 Handler 가 늘어나고, converRequest 와 같은 서브 클래스에서 구현해야 할 메서드가
늘어나면서 코드 파악이 갈수록 어려워진다는 단점은 일부 있었습니다. 뭐 단점이라고 하기엔 현 구조에선 어쩔 수 없는 것 같기도 하구요.
이러한 단점은 어떻게 해결해나가야 할 지 고민이 필요한 부분이지만 예시를 들어본 것이니 참고만 하시면 좋을 것 같습니다.
'Backend > 디자인 패턴' 카테고리의 다른 글
Middleware Pattern (미들웨어 패턴) (0) | 2022.11.06 |
---|---|
Strategy Pattern (전략 패턴) (0) | 2022.10.24 |
Adapter Pattern (어댑터 패턴) (0) | 2022.10.08 |
Decorator Pattern (데코레이터 패턴) (0) | 2022.10.01 |
Proxy Pattern (프록시 패턴) (0) | 2022.09.25 |