Pattern Decorator
Fa parte della sezione Programmazione orientata agli oggetti del percorso Swift di Coddy. Lezione 47 di 57.
Il pattern decorator aggiunge comportamento a un oggetto racchiudendolo in un altro oggetto con lo stesso protocollo. Il wrapper inoltra la chiamata all'oggetto racchiuso e aggiunge la propria parte prima o dopo:
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())Output:
espresso + milk
250Poiché un decoratore è a sua volta un Coffee, i decoratori possono avvolgersi a vicenda in qualsiasi combinazione e ordine, senza una sottoclasse per ogni combinazione:
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())Output:
espresso + milk + milk + syrup
330I decoratori si adattano ad aggiunte trasversali come la registrazione, la memorizzazione nella cache o la convalida applicate a un componente esistente, che rimane invariato:
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))Output:
fetching 7
row 7Il codice che usa l'oggetto vede solo il protocollo, quindi non può distinguere un oggetto decorato da uno semplice. È questo che rende sicuro aggiungere il pattern in un secondo momento.
func printReceipt(_ c: any Coffee) { // funziona per Espresso e per qualsiasi versione avvolta
print("\(c.label()): \(c.cost())")
}Sfida
FacileLe pizze vengono costruite con i decoratori. Il protocollo Pizza ha price() e toppings() (un array di nomi). Base costa 800 e non ha condimenti. Implementa i decoratori Cheese (+150), Olives (+100) e Double (raddoppia il prezzo di tutto ciò che contiene e ripete i condimenti due volte). Completa build(_:), che parte da Base e lo avvolge con un decoratore per ogni nome, nell'ordine indicato.
Il codice fornito legge righe di nomi di condimenti separati da virgole (o una riga vuota), costruisce ogni pizza e stampa 1050: cheese, olives o 800: plain.
Il tuo codice va inserito in Pizza.swift, Base.swift, Cheese.swift, Olives.swift, Double.swift e Functions.swift. main.swift contiene il codice di input/output fornito e non può essere modificato.
Provalo tu
// Código de entrada/salida proporcionado: déjalo tal 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: ", ")))
}
Questa lezione include un breve quiz. Inizia la lezione per rispondere e tenere traccia dei tuoi progressi.
Tutte le lezioni di Programmazione orientata agli oggetti
1Classi e oggetti
Lavorare con i fileDefinire le classiMetodi e selfInizializzatoriLe classi sono riferimentiRiepilogo - Tessera della biblioteca4Incapsulamento
Controllo degli accessiSola lettura dall’esternoProteggere lo statoInizializzatori che possono fallireRiepilogo - Conto bancario7Polimorfismo e tipi generici
PolimorfismoCasting dei tipiFunzioni genericheTipi genericiRipasso - Calcolatore di forme2Struct e tipi valore
Le structSemantica dei valoriMetodi mutantiStruct o classeRiepilogo - Articolo di inventario5Ereditarietà
SottoclassiSovrascrivere i metodiInizializzatori e superfinal e gerarchieRiepilogo - Gerarchia dei dipendenti8Protocolli standard
CustomStringConvertibleEquatableComparableHashableRiepilogo - Ordinamento personalizzato11Progetto: Gestione della biblioteca
Libri e utentiPrestito dei libriEsercitati da solo: Playground Swift