Pola Status
Termasuk bagian Pemrograman Berorientasi Objek dalam perjalanan Swift di Coddy. Pelajaran 49 dari 57.
Pola state memungkinkan object mengubah perilakunya saat state internalnya berubah. Setiap state memiliki tipenya sendiri yang menentukan apa yang terjadi dan state mana yang muncul berikutnya:
protocol LightState {
var name: String { get }
func next() -> any LightState
}
struct Red: LightState { var name: String { "red" }; func next() -> any LightState { Green() } }
struct Green: LightState { var name: String { "green" }; func next() -> any LightState { Yellow() } }
struct Yellow: LightState { var name: String { "yellow" }; func next() -> any LightState { Red() } }
var light: any LightState = Red()
for _ in 1...4 {
print(light.name)
light = light.next()
}Output:
red
green
yellow
redobject yang memiliki state meneruskan permintaan ke state saat ini. Setiap state menangani sebuah peristiwa dengan caranya sendiri, dan tindakan ilegal ditolak oleh state yang tidak mengizinkannya:
protocol OrderState {
var name: String { get }
func pay() -> (any OrderState)?
func ship() -> (any OrderState)?
}
struct New: OrderState { var name: String { "new" }; func pay() -> (any OrderState)? { Paid() }; func ship() -> (any OrderState)? { nil } }
struct Paid: OrderState { var name: String { "paid" }; func pay() -> (any OrderState)? { nil }; func ship() -> (any OrderState)? { Shipped() } }
struct Shipped: OrderState { var name: String { "shipped" }; func pay() -> (any OrderState)? { nil }; func ship() -> (any OrderState)? { nil } }
final class Order {
private(set) var state: any OrderState = New()
func handle(_ event: String) -> String {
guard let next = event == "pay" ? state.pay() : state.ship() else { return "cannot \(event) when \(state.name)" }
state = next
return "now \(state.name)"
}
}
let order = Order()
for e in ["ship", "pay", "pay", "ship"] { print(order.handle(e)) }Output:
cannot ship when new
now paid
cannot pay when paid
now shippedUntuk sejumlah kecil state tanpa datanya sendiri, enum dengan switch sering kali menyampaikan gagasan yang sama dengan lebih ringkas, sementara compiler memeriksa bahwa setiap state ditangani:
enum Door {
case open, closed, locked
func handle(_ action: String) -> Door? {
switch (self, action) {
case (.closed, "open"): return .open
case (.open, "close"): return .closed
case (.closed, "lock"): return .locked
case (.locked, "unlock"): return .closed
default: return nil
}
}
}
var door = Door.closed
for a in ["lock", "open", "unlock", "open"] {
if let next = door.handle(a) { door = next; print("\(a) -> \(door)") } else { print("cannot \(a)") }
}Output:
lock -> locked
cannot open
unlock -> closed
open -> openTipe state bermanfaat saat setiap state memiliki beberapa perilaku atau datanya sendiri. Dalam kedua kasus, aturan untuk setiap state berada di satu tempat, bukan tersebar dalam pemeriksaan if di seluruh object.
// tersebar: setiap method memeriksa state
func ship() { if status == "paid" { ... } else if status == "new" { ... } }
// pola state: setiap state merespons sendiri
state = state.ship() ?? stateTantangan
MudahModelkan mesin penjual otomatis dengan state enum Vending yang memiliki case idle, hasCoin(Int) dan soldOut. handle(_ event:) mengembalikan state berikutnya atau nil untuk event yang tidak diizinkan: coin <n> dalam idle beralih ke hasCoin(n), dan dalam hasCoin menambahkan jumlahnya; buy dalam hasCoin dengan nilai setidaknya 150 beralih ke idle (penjualan berhasil); refund dalam hasCoin beralih ke idle; empty dalam state apa pun beralih ke soldOut; refill dalam soldOut beralih ke idle.
Kode yang disediakan menerapkan event secara berurutan dan mencetak state setelah setiap event (idle, coin 100, sold out) atau not allowed: <event>.
Letakkan kodemu di Vending.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 machine = Vending.idle
for event in input {
if let next = machine.handle(event) {
machine = next
print(machine.label)
} else {
print("not allowed: \(event)")
}
}
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