Pola Builder
Termasuk bagian Pemrograman Berorientasi Objek dalam perjalanan Swift di Coddy. Pelajaran 48 dari 57.
Pola builder menyusun object kompleks langkah demi langkah. Setiap langkah mengatur satu bagian dan mengembalikan builder, sehingga langkah-langkahnya bisa dirangkai, lalu build() terakhir membuat object yang sudah selesai:
struct Request {
let url: String
let method: String
let headers: [String: String]
}
struct RequestBuilder {
private var url = ""
private var method = "GET"
private var headers: [String: String] = [:]
func url(_ u: String) -> RequestBuilder { var b = self; b.url = u; return b }
func method(_ m: String) -> RequestBuilder { var b = self; b.method = m; return b }
func header(_ k: String, _ v: String) -> RequestBuilder { var b = self; b.headers[k] = v; return b }
func build() -> Request { Request(url: url, method: method, headers: headers) }
}
let req = RequestBuilder().url("/users").method("POST").header("Auth", "token").build()
print("\(req.method) \(req.url) \(req.headers.count) header")Output:
POST /users 1 headerBuilder dapat memeriksa seluruh konfigurasi sebelum membuat object, sehingga object yang tidak valid tidak pernah dibuat. Di sini, build() melempar error jika bagian yang wajib tidak ada:
enum BuildError: Error { case missingURL }
struct Request { let url: String; let method: String }
struct RequestBuilder {
private var url: String?
private var method = "GET"
func url(_ u: String) -> RequestBuilder { var b = self; b.url = u; return b }
func method(_ m: String) -> RequestBuilder { var b = self; b.method = m; return b }
func build() throws -> Request {
guard let url else { throw BuildError.missingURL }
return Request(url: url, method: method)
}
}
do {
_ = try RequestBuilder().method("PUT").build()
} catch {
print("cannot build: \(error)")
}Output:
cannot build: missingURLSetiap langkah menyalin struct dan mengubah salinannya, sehingga builder yang sudah dikonfigurasi sebagian dapat digunakan kembali sebagai templat untuk beberapa object:
struct PizzaBuilder {
private var size = "medium"
private var toppings: [String] = []
func size(_ s: String) -> PizzaBuilder { var b = self; b.size = s; return b }
func add(_ t: String) -> PizzaBuilder { var b = self; b.toppings.append(t); return b }
func build() -> String { "\(size) pizza with " + (toppings.isEmpty ? "nothing" : toppings.joined(separator: ", ")) }
}
let base = PizzaBuilder().size("large").add("cheese")
print(base.add("ham").build())
print(base.add("olives").build())Output:
large pizza with cheese, ham
large pizza with cheese, olivesNilai parameter default Swift sudah mencakup kasus sederhana (Request(url: "/", method: "GET")). Builder bermanfaat saat sebuah object memiliki banyak bagian opsional, bagian-bagian yang saling bergantung, atau aturan yang harus diperiksa sebelum object itu bisa ada.
// sederhana: argumen bawaan sudah cukup
struct Point { var x = 0, y = 0 }
// kompleks: banyak bagian opsional dan validasi -> builder
let report = ReportBuilder().title("Q3").add(section: s1).add(section: s2).footer("draft").build()Tantangan
MudahBuat builder untuk pesan email. EmailBuilder memiliki langkah-langkah yang bisa dirangkai, yaitu to(_:) (bisa dipanggil beberapa kali untuk menambahkan penerima), subject(_:), body(_:), dan urgent(). build() mengembalikan Email atau melempar EmailError.noRecipients atau EmailError.noSubject. Email mendesak mendapat awalan [URGENT] pada subjeknya.
Kode yang disediakan membaca perintah untuk setiap email yang dipisahkan oleh baris --- (to ada@x.io, subject Hello, body text, urgent, lalu send) dan mencetak To: ada@x.io, bo@x.io | [URGENT] Hello | text, error: no recipients, atau error: no subject.
Tulis kodemu di Email.swift, EmailError.swift, dan EmailBuilder.swift. main.swift berisi kode input/output yang disediakan dan tidak boleh diedit.
Coba sendiri
// Kode input/output yang disediakan: biarkan apa adanya
var input: [String] = []
while let line = readLine() { input.append(line) }
var builder = EmailBuilder()
for line in input {
let p = line.split(separator: " ", maxSplits: 1).map(String.init)
switch p[0] {
case "to": builder = builder.to(p[1])
case "subject": builder = builder.subject(p[1])
case "body": builder = builder.body(p[1])
case "urgent": builder = builder.urgent()
case "send":
do {
let e = try builder.build()
print("To: \(e.recipients.joined(separator: ", ")) | \(e.subject) | \(e.body)")
} catch EmailError.noRecipients {
print("error: no recipients")
} catch {
print("error: no subject")
}
default: builder = EmailBuilder()
}
}
Pelajaran ini berisi kuis singkat. Mulai pelajarannya untuk menjawab kuis dan melacak progresmu.
Semua pelajaran di Pemrograman Berorientasi Objek
1Class dan Object
Bekerja dengan FileMendefinisikan ClassMethod dan selfInitializerClass adalah ReferensiUlasan: Kartu Perpustakaan4Enkapsulasi
Kontrol AksesHanya Bisa Dibaca dari LuarMelindungi StateInitializer yang Bisa GagalRangkuman: Rekening Bank7Polimorfisme dan Generik
PolimorfismeKonversi TipeFungsi GenerikTipe GenerikRangkuman: Kalkulator Bentuk2Struct dan Tipe Nilai
StructSemantik NilaiMethod yang Mengubah NilaiStruct atau classRangkuman, Item Inventaris11Proyek: Manajemen Perpustakaan
Buku dan AnggotaPeminjaman BukuLatihan sendiri: Playground Swift