Melindungi State
Termasuk bagian Pemrograman Berorientasi Objek dalam perjalanan Swift di Coddy. Pelajaran 19 dari 57.
Invarian adalah aturan yang harus selalu berlaku untuk suatu nilai, seperti "saldo tidak pernah negatif". Tipe melindungi invariannya dengan memeriksa setiap perubahan sebelum menerapkannya:
struct BankAccount {
private(set) var balance = 0
mutating func withdraw(_ amount: Int) -> Bool {
guard amount > 0, amount <= balance else { return false }
balance -= amount
return true
}
mutating func deposit(_ amount: Int) {
guard amount > 0 else { return }
balance += amount
}
}
var acc = BankAccount()
acc.deposit(100)
print(acc.withdraw(150))
print(acc.withdraw(40))
print(acc.balance)Output:
false
true
60Ketika pemanggil perlu mengetahui alasan perubahan ditolak, method dapat melempar error alih-alih mengembalikan false. Tipe error adalah enum yang sesuai dengan Error:
enum TransferError: Error {
case invalidAmount
case insufficientFunds(missing: Int)
}
struct Account {
private(set) var balance: Int
mutating func withdraw(_ amount: Int) throws {
guard amount > 0 else { throw TransferError.invalidAmount }
guard amount <= balance else { throw TransferError.insufficientFunds(missing: amount - balance) }
balance -= amount
}
}
var acc = Account(balance: 30)
do {
try acc.withdraw(50)
} catch TransferError.insufficientFunds(let missing) {
print("missing \(missing)")
} catch {
print("other error")
}Output:
missing 20Letakkan setiap perubahan pada data yang dilindungi di dalam method yang memeriksanya. Jika property dapat diatur dari luar, baris kode mana pun dapat melanggar aturan tanpa diketahui oleh tipe tersebut:
struct Temperature {
private(set) var kelvin: Double // harus tetap >= 0
mutating func cool(by amount: Double) {
kelvin = max(0, kelvin - amount) // satu-satunya cara untuk menurunkan nilainya
}
}Operasi yang mengubah beberapa properti harus menjaga semuanya tetap konsisten, bahkan jika operasi gagal di tengah jalan. Periksa semuanya terlebih dahulu, lalu ubah statusnya:
struct Inventory {
private(set) var stock: [String: Int] = ["tea": 2, "jam": 1]
mutating func sell(_ items: [String]) -> Bool {
var needed: [String: Int] = [:]
for i in items { needed[i, default: 0] += 1 }
for (item, n) in needed where (stock[item] ?? 0) < n { return false }
for (item, n) in needed { stock[item]! -= n }
return true
}
}
var inv = Inventory()
print(inv.sell(["tea", "jam", "jam"]))
print(inv.stock["tea"]!)
print(inv.sell(["tea", "jam"]))
print(inv.stock["tea"]!)Output:
false
2
true
1Tantangan
MudahLengkapi struct Seats, yang menjual tiket untuk sebuah pertunjukan dengan capacity kursi. sold bersifat private(set). buy(_:) melempar TicketError.invalidCount jika jumlahnya kurang dari 1, TicketError.soldOut jika tidak ada kursi tersisa, dan TicketError.notEnough(left:) jika jumlah kursi tersisa lebih sedikit daripada yang diminta. Jika tidak, fungsi ini menambahkan tiket ke sold.
Kode yang disediakan membaca kapasitas dan satu jumlah yang diminta pada setiap baris. Untuk setiap jumlah, kode mencetak sold 3, left 7, invalid count, sold out atau only 2 left.
Tulis kodemu di TicketError.swift dan Seats.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 seats = Seats(capacity: Int(input[0])!)
for line in input.dropFirst() {
let n = Int(line)!
do {
try seats.buy(n)
print("sold \(n), left \(seats.capacity - seats.sold)")
} catch TicketError.invalidCount {
print("invalid count")
} catch TicketError.soldOut {
print("sold out")
} catch TicketError.notEnough(let left) {
print("only \(left) left")
} catch {
print("unexpected")
}
}
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