Durum Kalıbı
Coddy'nin Swift Journey'sinin Nesne Yönelimli Programlama bölümünün bir parçası. Ders 49 / 57.
Durum deseni, bir nesnenin iç durumu değiştiğinde davranışını değiştirmesini sağlar. Her durum, ne olacağına ve bundan sonra hangi durumun geleceğine karar veren kendi türüdür:
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()
}Çıktı:
red
green
yellow
redDuruma sahip olan nesne, istekleri mevcut durumuna iletir. Her durum bir olayı kendi yöntemiyle ele alır ve izin verilmeyen eylemlere, bunlara izin vermeyen durumlar tarafından karşı çıkılır:
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)) }Çıktı:
cannot ship when new
now paid
cannot pay when paid
now shippedKendi verilerine sahip olmayan az sayıda durum için, switch içeren bir enum genellikle aynı fikri daha özlü bir şekilde ifade eder; derleyici de her durumun ele alındığını kontrol eder:
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)") }
}Çıktı:
lock -> locked
cannot open
unlock -> closed
open -> openDurum türleri, her durumun birden fazla davranışı veya kendine ait verileri olduğunda işe yarar. Her iki durumda da her durumun kuralları, nesnenin geneline yayılmış if kontrolleri yerine tek bir yerde bulunur.
// dağınık: her metot durumu kontrol eder
func ship() { if status == "paid" { ... } else if status == "new" { ... } }
// durum deseni: her durum kendi adına cevap verir
state = state.ship() ?? stateGörev
Kolayidle, hasCoin(Int) ve soldOut durumlarına sahip bir enum durumu Vending ile bir otomat modelleyin. handle(_ event:), bir sonraki durumu veya izin verilmeyen bir etkinlik için nil döndürür: idle durumundaki coin <n>, hasCoin(n) durumuna geçer ve hasCoin durumunda miktara ekleme yapar; hasCoin durumunda en az 150 ile buy, idle durumuna geçer (başarılı bir satış); hasCoin durumunda refund, idle durumuna geçer; herhangi bir durumdaki empty, soldOut durumuna geçer; soldOut durumundaki refill, idle durumuna geçer.
Sağlanan kod, etkinlikleri sırayla uygular ve her birinden sonra durumu (idle, coin 100, sold out) veya not allowed: <event> yazdırır.
Kodunuz Vending.swift dosyasına gelir. main.swift, sağlanan girdi/çıktı kodunu içerir ve düzenlenemez.
Kendin dene
// Sağlanan giriş/çıkış kodu: olduğu gibi bırakın
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)")
}
}
Bu ders kısa bir quiz içerir. Soruları yanıtlamak ve ilerlemeni kaydetmek için derse başla.
Nesne Yönelimli Programlama bölümündeki tüm dersler
1Sınıflar ve Nesneler
Dosyalarla ÇalışmaSınıfları TanımlamaMetotlar ve selfBaşlatıcılarSınıflar ReferanstırTekrar - Kütüphane Kartı4Kapsülleme
Erişim DenetimiDışarıdan Salt OkunurDurumu KorumaBaşarısız Olabilen BaşlatıcılarTekrar - Banka Hesabı7Polimorfizm ve Generic'ler
PolimorfizmTür DönüşümüGeneric FonksiyonlarGeneric TürlerTekrar - Şekil Hesaplayıcı2Struct Yapıları ve Değer Türleri
Struct YapılarıDeğer SemantiğiDeğiştirici MetotlarStruct mı Class mıTekrar - Envanter Öğesi5Kalıtım
Alt sınıflarMetotları Geçersiz KılmaBaşlatıcılar ve superfinal ve HiyerarşilerTekrar - Çalışan Hiyerarşisi11Proje: Kütüphane Yönetimi
Kitaplar ve ÜyelerKitap Ödünç AlmaKendi başına pratik yap: Swift playground