Menu
Coddy logo textTech

Delegasyon Kalıbı

Coddy'nin Swift Journey'sinin Nesne Yönelimli Programlama bölümünün bir parçası. Ders 46 / 57.

Delegasyon, bir nesnenin bazı kararları bir protokol aracılığıyla başka bir nesneye, yani delegesine, devretmesini sağlar. Nesne kendi işini yapar ve değişkenlik gösteren noktalarda delegesine danışır. Apple'ın framework'leri bu kalıbı her yerde kullanır:

protocol DownloadDelegate: AnyObject {
    func progress(_ percent: Int)
    func finished(_ file: String)
}

final class Downloader {
    weak var delegate: DownloadDelegate?

    func download(_ file: String) {
        for p in [50, 100] { delegate?.progress(p) }
        delegate?.finished(file)
    }
}

final class Screen: DownloadDelegate {
    func progress(_ percent: Int) { print("\(percent)%") }
    func finished(_ file: String) { print("done: \(file)") }
}

let screen = Screen()
let d = Downloader()
d.delegate = screen
d.download("photo.png")

Çıktı:

50%
100%
done: photo.png

Delege özelliği isteğe bağlıdır ve çağrılarda delegate?. kullanılır; bu nedenle kimse dinlemiyor olsa bile nesne çalışır. weak olarak tanımlandığından nesne, delege nesnesini kendi başına canlı tutmaz; bu da birbirlerine işaret eden nesneler arasındaki güçlü referans döngülerini önler:

weak var delegate: DownloadDelegate?   // protokolün yalnızca sınıf olması gerekir: AnyObject
delegate?.finished(file)               // delegate yokken hiçbir şey yapmaz

Bir delegate ayrıca soruları yanıtlayabilir; bu da alt sınıflandırma yapmadan nesnenin davranışını özelleştirmesine olanak tanır:

protocol ListDelegate: AnyObject {
    func shouldShow(_ item: String) -> Bool
}

final class ListView {
    weak var delegate: ListDelegate?
    func render(_ items: [String]) -> [String] {
        items.filter { delegate?.shouldShow($0) ?? true }
    }
}

final class HideDrafts: ListDelegate {
    func shouldShow(_ item: String) -> Bool { !item.hasPrefix("draft") }
}

let view = ListView()
let rules = HideDrafts()
print(view.render(["a", "draft b"]))
view.delegate = rules
print(view.render(["a", "draft b"]))

Çıktı:

["a", "draft b"]
["a"]

Delegasyon, gözlemci deseninden farklıdır: Bir nesnenin kendisine sorular sorduğu ve bilgi verdiği bir delegesi vardır; buna karşın bir konu, yalnızca bilgilendirdiği birçok gözlemciye sahip olabilir.

// delegation: bir partner, soruları yanıtlayabilir
weak var delegate: TableDelegate?
// observer: herhangi sayıda dinleyici, yalnızca bilgilendirilir
private var observers: [(Event) -> Void] = []
challenge icon

Görev

Kolay

Bir Checkout, kararlar için temsilcisinden bilgi ister. Yalnızca sınıflar için olan CheckoutDelegate protokolünde discount(for total: Int) -> Int ve didComplete(total: Int) bulunur. Checkout içinde bir weak var delegate bulunur ve pay(_ prices: [Int]) -> Int fiyatları toplar, temsilcinin indirimini çıkarır (temsilci yoksa 0), temsilciye nihai toplamı bildirir ve bu toplamı döndürür. Toplamı 100 veya daha fazla olan işlemlerde %10 indirim yapan ve tamamlanan her toplamı receipts içinde kaydeden bir temsilci olan LoyaltyShop'u uygulayın.

Sağlanan kod, virgülle ayrılmış fiyat satırlarını okur. İlk satır için temsilci olmadan, diğer satırlar için ise bir LoyaltyShop ile ödeme yapar; her toplamı yazdırır ve son olarak receipts: 120 90 çıktısını verir.

Kodunuz CheckoutDelegate.swift, Checkout.swift ve LoyaltyShop.swift dosyalarına yazılmalıdır. main.swift, sağlanan girdi/çıktı kodunu içerir ve düzenlenemez.

Kendin dene

// Sağlanan girdi/çıktı kodu: olduğu gibi bırakın
var input: [String] = []
while let line = readLine() { input.append(line) }
let checkout = Checkout()
let shop = LoyaltyShop()
for (i, line) in input.enumerated() {
    if i == 1 { checkout.delegate = shop }
    print(checkout.pay(line.split(separator: ",").map { Int($0)! }))
}
print("receipts: " + shop.receipts.map { String($0) }.joined(separator: " "))
quiz iconKendini test et

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

Kendi başına pratik yap: Swift playground