Padrão Decorator
Parte da seção Programação Orientada a Objetos do Journey de Swift da Coddy. Lição 47 de 57.
O padrão decorator adiciona comportamento a um objeto encapsulando-o em outro objeto com o mesmo protocolo. O encapsulador encaminha a chamada para o objeto encapsulado e adiciona sua própria parte antes ou depois:
protocol Coffee {
func cost() -> Int
func label() -> String
}
struct Espresso: Coffee {
func cost() -> Int { 200 }
func label() -> String { "espresso" }
}
struct WithMilk: Coffee {
let base: any Coffee
func cost() -> Int { base.cost() + 50 }
func label() -> String { base.label() + " + milk" }
}
let drink = WithMilk(base: Espresso())
print(drink.label())
print(drink.cost())Saída:
espresso + milk
250Como um decorador é, por si só, um Coffee, os decoradores podem envolver uns aos outros em qualquer combinação e ordem, sem uma subclasse para cada combinação:
protocol Coffee { func cost() -> Int; func label() -> String }
struct Espresso: Coffee { func cost() -> Int { 200 }; func label() -> String { "espresso" } }
struct WithMilk: Coffee {
let base: any Coffee
func cost() -> Int { base.cost() + 50 }
func label() -> String { base.label() + " + milk" }
}
struct WithSyrup: Coffee {
let base: any Coffee
func cost() -> Int { base.cost() + 30 }
func label() -> String { base.label() + " + syrup" }
}
let fancy = WithSyrup(base: WithMilk(base: WithMilk(base: Espresso())))
print(fancy.label())
print(fancy.cost())Saída:
espresso + milk + milk + syrup
330Decoradores são adequados para adicionar funcionalidades transversais, como registro, armazenamento em cache ou validação, em torno de um componente existente, que permanece inalterado:
protocol DataSource { func fetch(_ id: Int) -> String }
struct Database: DataSource { func fetch(_ id: Int) -> String { "row \(id)" } }
struct Logged: DataSource {
let inner: any DataSource
func fetch(_ id: Int) -> String {
print("fetching \(id)")
return inner.fetch(id)
}
}
let source: any DataSource = Logged(inner: Database())
print(source.fetch(7))Saída:
fetching 7
row 7O código que usa o objeto vê apenas o protocolo, portanto não consegue distinguir um objeto decorado de um objeto simples. É isso que torna seguro adicionar o padrão posteriormente.
func printReceipt(_ c: any Coffee) { // funciona para Espresso e para qualquer versão encapsulada
print("\(c.label()): \(c.cost())")
}Desafio
FácilAs pizzas são construídas com decoradores. O protocolo Pizza tem price() e toppings() (um array de nomes). Base custa 800 e não tem coberturas. Implemente os decoradores Cheese (+150), Olives (+100) e Double (dobra o preço de tudo que está dentro dele e repete suas coberturas duas vezes). Complete build(_:), que começa com Base e o envolve com um decorador por nome, na ordem.
O código fornecido lê linhas com nomes de coberturas separados por vírgulas (ou uma linha vazia), constrói cada pizza e imprime 1050: cheese, olives ou 800: plain.
Seu código deve ficar em Pizza.swift, Base.swift, Cheese.swift, Olives.swift, Double.swift e Functions.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) }
for line in input {
let names = line.isEmpty ? [] : line.split(separator: ",").map(String.init)
let p = build(names)
let tops = p.toppings()
print("\(p.price()): " + (tops.isEmpty ? "plain" : tops.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