Skip to content

Instantly share code, notes, and snippets.

@cozzin
Last active May 26, 2021 06:24
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save cozzin/6b9cd72000bcbe98efccd557d4f904ab to your computer and use it in GitHub Desktop.
Save cozzin/6b9cd72000bcbe98efccd557d4f904ab to your computer and use it in GitHub Desktop.
Builder Pattern
protocol Builder {
func make(title: String)
func make(string: String)
func make(items: [String])
func close()
}
final class BuilderTests: XCTestCase {
func testTextBuilder() throws {
let textBuilder = TextBuilder()
let director = Director(builder: textBuilder)
director.construct()
let result = textBuilder.result()
XCTAssertEqual(
result,
"""
==========================
『Gretting』
◼ 아침과 낮에
· 좋은 아침입니다.
· 안녕하세요.
◼ 밤에
· 안녕하세요
· 안녕히 주무세요.
· 안녕히 계세요.
==========================
"""
)
}
func testHTMLBuilder() throws {
let htmlBuilder = HTMLBuilder()
let director = Director(builder: htmlBuilder)
director.construct()
XCTAssertEqual(htmlBuilder.filename(), "Gretting.html")
XCTAssertEqual(
htmlBuilder.result(),
"""
<html><head><title>Gretting</title></head><body>
<h1>Gretting</h1>
<p>아침과 낮에</p>
<ul>
<li>좋은 아침입니다.</li>
<li>안녕하세요.</li>
</ul>
<p>밤에</p>
<ul>
<li>안녕하세요</li>
<li>안녕히 주무세요.</li>
<li>안녕히 계세요.</li>
</ul>
</body></html>
"""
)
}
}
final class Director {
private let builder: Builder
init(builder: Builder) {
self.builder = builder
}
func construct() {
builder.make(title: "Gretting")
builder.make(string: "아침과 낮에")
builder.make(items: [
"좋은 아침입니다.",
"안녕하세요."
])
builder.make(string: "밤에")
builder.make(items: [
"안녕하세요",
"안녕히 주무세요.",
"안녕히 계세요."
])
builder.close()
}
}
final class HTMLBuilder: Builder {
private var writer: PrintWriter?
func make(title: String) {
writer = PrintWriter(filename: title + ".html")
writer?.println("<html><head><title>" + title + "</title></head><body>")
writer?.println("<h1>" + title + "</h1>")
}
func make(string: String) {
writer?.println("<p>" + string + "</p>")
}
func make(items: [String]) {
writer?.println("<ul>")
items.forEach {
writer?.println("<li>\($0)</li>")
}
writer?.println("</ul>")
}
func close() {
writer?.println("</body></html>")
do {
try writer?.close()
} catch {
print("[PrintWriter] error: \(error)")
}
}
func filename() -> String? {
return writer?.filename
}
func result() -> String? {
return writer?.result()
}
}
final class PrintWriter {
enum Exception: Error {
case fileWriteException(Error)
case invalidfileURL
}
fileprivate let filename: String
private let fileURL: URL
private var contents: String
init?(filename: String) {
guard let fileURL = FileManager
.default
.urls(for: .documentDirectory, in: .userDomainMask)
.first?
.appendingPathComponent(filename) else {
return nil
}
self.filename = filename
self.fileURL = fileURL
self.contents = ""
}
func println(_ text: String) {
contents.append(text + "\n")
}
func close() throws {
try contents.write(to: fileURL, atomically: true, encoding: .utf8)
}
func result() -> String {
return contents
}
}
final class TextBuilder: Builder {
private var buffer: String = ""
func make(title: String) {
buffer.append("==========================\n")
buffer.append("『\(title)』")
buffer.append("\n")
}
func make(string: String) {
buffer.append("◼ \(string)\n")
buffer.append("\n")
}
func make(items: [String]) {
buffer.append(contentsOf: items.flatMap { " · \($0)\n" })
buffer.append("\n")
}
func close() {
buffer.append("==========================\n")
}
func result() -> String {
return buffer
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment