Padrão de Delegação
Parte da seção Programação Orientada a Objetos do Journey de Swift da Coddy. Lição 46 de 57.
Delegação permite que um objeto transfira algumas decisões para outro objeto, seu delegado, por meio de um protocolo. O objeto realiza seu trabalho e consulta o delegado nos pontos que variam. Os frameworks da Apple usam esse padrão em todos os lugares:
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")Saída:
50%
100%
done: photo.pngA propriedade delegate é opcional e as chamadas usam delegate?., portanto o objeto funciona mesmo quando ninguém está escutando. Ela é declarada como weak para que o objeto não mantenha seu delegate ativo por conta própria, o que evita ciclos de retenção entre objetos que apontam uns para os outros:
weak var delegate: DownloadDelegate? // requer que o protocolo seja apenas de classe: AnyObject
delegate?.finished(file) // não faz nada quando não há delegateUm delegado também pode responder a perguntas, o que permite personalizar o comportamento do objeto sem criar uma subclasse:
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"]))Saída:
["a", "draft b"]
["a"]A delegação difere do padrão observer: um objeto tem um único delegado a quem faz perguntas e informa, enquanto um sujeito pode ter muitos observadores aos quais apenas informa.
// delegação: um parceiro, pode responder perguntas
weak var delegate: TableDelegate?
// observador: qualquer número de ouvintes, apenas notificados
private var observers: [(Event) -> Void] = []Desafio
FácilUm Checkout pede decisões ao seu delegado. O protocolo CheckoutDelegate (somente para classes) possui discount(for total: Int) -> Int e didComplete(total: Int). Checkout tem uma weak var delegate, e pay(_ prices: [Int]) -> Int soma os preços, subtrai o desconto do delegado (0 sem um delegado), informa ao delegado o total final e o retorna. Implemente LoyaltyShop, um delegado que oferece 10% de desconto para totais de 100 ou mais e registra cada total concluído em receipts.
O código fornecido lê linhas de preços separados por vírgulas. Ele paga a primeira linha sem um delegado e as demais com um LoyaltyShop, imprime cada total e, por fim, receipts: 120 90.
Seu código deve estar em CheckoutDelegate.swift, Checkout.swift e LoyaltyShop.swift. main.swift contém o código fornecido de entrada/saída e não pode ser editado.
Experimente você mesmo
// Código de entrada/saída fornecido: mantenha-o como está
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: " "))
Esta lição inclui um quiz rápido. Comece a lição para respondê-lo e acompanhar seu progresso.
Todas as lições de Programação Orientada a Objetos
1Classes e Objetos
Trabalhando com ArquivosDefinindo ClassesMétodos e selfInicializadoresClasses são ReferênciasRevisão - Cartão da Biblioteca4Encapsulamento
Controle de AcessoSomente Leitura ExternaProtegendo o EstadoInicializadores que Podem FalharRevisão - Conta Bancária7Polimorfismo e Genéricos
PolimorfismoConversão de TiposFunções GenéricasTipos GenéricosRevisão - Calculadora de Formas2Structs e Tipos de Valor
StructsSemântica de ValorMétodos MutáveisStruct ou ClasseRecapitulação - Item de Inventário5Herança
SubclassesSobrescrita de métodosInicializadores e superfinal e hierarquiasRecapitulação - Hierarquia de funcionários8Protocolos Padrão
CustomStringConvertibleEquatableComparableHashableRecapitulação - Ordenação Personalizada11Projeto: Gerenciamento de Biblioteca
Livros e MembrosEmpréstimo de LivrosPratique por conta própria: Playground de Swift