A WWDC 2015 session video descrive l'idea di Programmazione orientata al protocollo e voglio adottare questa tecnica nelle mie future app. Ho giocato con Swift 2.0 negli ultimi due giorni per capire questo nuovo approccio e sono bloccato nel tentativo di farlo funzionare con lo Delegate Pattern.Programmazione orientata al protocollo e il pattern delegato
ho due protocolli che definiscono la struttura di base della parte interessante del mio progetto (il codice di esempio è una sciocchezza, ma descrive il problema):
1) Un protocollo delegazione che rende accessibili alcune informazioni, simile a dataSource protocollo di UITableViewController:
protocol ValueProvider {
var value: Int { get }
}
2) Un protocollo interfaccia del soggetto che fa qualcosa con le informazioni da abo ve (qui è dove l'idea di un approccio "Protocollo-First" entra in gioco):
protocol DataProcessor {
var provider: ValueProvider { get }
func process() -> Int
}
Per quanto riguarda l'effettiva attuazione del Titolare del trattamento, ora posso scegliere tra enumerazioni, le strutture, e le classi. Ci sono diversi livelli di astrazione di come voglio elaborare le informazioni, quindi le classi sembrano adattarsi al meglio (tuttavia non voglio rendere questa decisione definitiva, in quanto potrebbe cambiare in casi d'uso futuri). Posso definire una classe di processore di base, in cima alla quale posso costruire diversi processori casi specifici (non possibile con le strutture e le enumerazioni):
class BaseDataProcessor: DataProcessor {
let provider: ValueProvider
init(provider: ValueProvider) {
self.provider = provider
}
func process() -> Int {
return provider.value + 100
}
}
class SpecificDataProcessor: BaseDataProcessor {
override func process() -> Int {
return super.process() + 200
}
}
Fino a qui tutto funziona come un fascino. Tuttavia, in realtà i processori di dati specifici sono strettamente vincolati ai valori elaborati (al contrario del processore di base, per cui questo è non true), tale che voglio integrare il valore ValueProvider direttamente nella sottoclasse (per confronto: spesso UITableViewControllers è il proprio data source e delegato).
primo momento ho pensato di aggiungere un protocollo di estensione con un'implementazione di default:
extension DataProcessor where Self: ValueProvider {
var provider: ValueProvider { return self }
}
questo probabilmente funzionerà se non ho avuto la classe BaseDataProcessor che io non voglio fare il valore-bound. Tuttavia, le sottoclassi che ereditano da BaseDataProcessor e adottano ValueProvider sembrano sovrascrivere quella implementazione internamente, quindi questa non è un'opzione.
ho continuato a sperimentare e finito con questo:
class BaseDataProcessor: DataProcessor {
// Yes, that's ugly, but I need this 'var' construct so I can override it later
private var _provider: ValueProvider!
var provider: ValueProvider { return _provider }
func process() -> Int {
return provider.value + 10
}
}
class SpecificDataProcessor: BaseDataProcessor, ValueProvider {
let value = 1234
override var provider: ValueProvider { return self }
override func process() -> Int {
return super.process() + 100
}
}
che riunisce e, a prima vista sembra fare quello che voglio. Tuttavia, questa non è una soluzione in quanto produce un ciclo di riferimento, che può essere visto in un parco giochi Swift:
weak var p: SpecificDataProcessor!
autoreleasepool {
p = SpecificDataProcessor()
p.process()
}
p // <-- not nil, hence reference cycle!
Un'altra opzione potrebbe essere quella di aggiungere vincoli di classe alle definizioni di protocollo. Tuttavia, questo potrebbe rompere l'approccio POP come lo comprendo.
Concludendo, penso che la mia domanda si riduce a quanto segue: Come si fa a programmare la programmazione orientata ai protocolli e il Delegate Pattern senza limitarsi ai vincoli di classe durante la progettazione del protocollo?