+TypeScript 예제
제목과 행을 넣는 순서는 ReportRecipe에, 각 단계를 텍스트나 HTML로 만드는 방법은 빌더에 둔다. 그래서 순서를 바꾸는 일과 출력 표현을 바꾸는 일을 따로 고칠 수 있다.
// 조립 순서를 형식별 클래스에 복사하지 않도록 공통 단계만 정한다.
interface IReportBuilder {
title(value: string): void;
row(value: string): void;
finish(): string;
}
class TextBuilder implements IReportBuilder {
private readonly parts: string[] = [];
title(value: string): void { this.parts.push(value); }
row(value: string): void { this.parts.push("- " + value); }
finish(): string { return this.parts.join("\n"); }
}
function htmlText(value: string): string {
return value.replaceAll("&", "&").replaceAll("<", "<")
.replaceAll(">", ">").replaceAll('"', """).replaceAll("'", "'");
}
class HtmlBuilder implements IReportBuilder {
private readonly parts: string[] = [];
title(value: string): void { this.parts.push("<h1>" + htmlText(value) + "</h1>"); }
row(value: string): void { this.parts.push("<p>" + htmlText(value) + "</p>"); }
finish(): string { return this.parts.join(""); }
}
// 순서는 이곳에서 정하고, 실제 표현은 전달받은 빌더에 맡긴다.
class ReportRecipe {
static build(builder: IReportBuilder): string {
builder.title("Report");
builder.row("A < B");
return builder.finish();
}
}
console.log(ReportRecipe.build(new TextBuilder()));
console.log(ReportRecipe.build(new HtmlBuilder()));
Report
- A < B
<h1>Report</h1><p>A < B</p>
HTML은 텍스트 위치에 넣을 값을 인코딩한다. 각 빌더는 보고서마다 새로 만들며 finish()는 상태를 초기화하지 않는다.