Patron de délégation
Fait partie de la section Programmation orientée objet du Journey Swift de Coddy. Leçon 46 sur 57.
La délégation permet à un objet de confier certaines décisions à un autre objet, son délégué, par l’intermédiaire d’un protocole. L’objet effectue son travail et interroge le délégué aux points qui varient. Les frameworks d’Apple utilisent ce modèle partout :
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")Sortie :
50%
100%
done: photo.pngLa propriété delegate est facultative et les appels utilisent delegate?., de sorte que l’objet fonctionne même lorsque personne n’écoute. Elle est déclarée weak afin que l’objet ne maintienne pas à lui seul son delegate en vie, ce qui évite les cycles de rétention entre les objets qui pointent l’un vers l’autre :
weak var delegate: DownloadDelegate? // nécessite que le protocole soit réservé aux classes : AnyObject
delegate?.finished(file) // ne fait rien quand il n'y a pas de delegateUn délégué peut également répondre à des questions, ce qui lui permet de personnaliser le comportement de l'objet sans créer de sous-classe :
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"]))Sortie :
["a", "draft b"]
["a"]La délégation diffère du patron observateur : un objet possède un délégué qu’il interroge et informe, tandis qu’un sujet peut avoir de nombreux observateurs qu’il informe uniquement.
// délégation : un partenaire, peut répondre aux questions
weak var delegate: TableDelegate?
// observateur : un nombre quelconque d'écouteurs, notifiés uniquement
private var observers: [(Event) -> Void] = []Défi
FacileUn Checkout demande des décisions à son délégué. Le protocole CheckoutDelegate (réservé aux classes) possède discount(for total: Int) -> Int et didComplete(total: Int). Checkout possède un weak var delegate, et pay(_ prices: [Int]) -> Int additionne les prix, soustrait la remise du délégué (0 sans délégué), informe le délégué du total final et le renvoie. Implémentez LoyaltyShop, un délégué qui accorde une remise de 10 % sur les totaux supérieurs ou égaux à 100 et enregistre chaque total finalisé dans receipts.
Le code fourni lit des lignes de prix séparés par des virgules. Il effectue le paiement de la première ligne sans délégué et celui des autres avec un LoyaltyShop, affiche chaque total et enfin receipts: 120 90.
Votre code doit se trouver dans CheckoutDelegate.swift, Checkout.swift et LoyaltyShop.swift. main.swift contient le code d’entrée/sortie fourni et ne peut pas être modifié.
Essayez vous-même
// Code d'entrée/sortie fourni : le garder tel quel
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: " "))
Cette leçon comprend un petit quiz. Commencez la leçon pour y répondre et suivre votre progression.
Toutes les leçons de Programmation orientée objet
1Classes et objets
Travailler avec des fichiersDéfinir des classesMéthodes et selfInitialiseursLes classes sont des référencesRécapitulatif - Carte de bibliothèque4Encapsulation
Contrôle d’accèsLecture seule depuis l’extérieurProtection de l’étatInitialiseurs pouvant échouerRécapitulatif - Compte bancaire7Polymorphisme et génériques
PolymorphismeConversion de typeFonctions génériquesTypes génériquesRécapitulatif - Calculateur de formes2Structures et types valeur
StructuresSémantique de valeurMéthodes mutantesStructure ou classeRécapitulatif - article d’inventaire5Héritage
Sous-classesRedéfinition des méthodesInitialiseurs et superfinal et hiérarchiesRécapitulatif - hiérarchie des employés8Protocoles standard
CustomStringConvertibleEquatableComparableHashableRécapitulatif - Tri personnalisé11Projet : Gestion de bibliothèque
Livres et membresEmprunter des livresEntraînez-vous par vous-même : Playground Swift