Per quali motivi useresti un'estensione di classe separata per ogni delegato in Swift?


13

Stavo lavorando attraverso un tutorial di Ray Wenderlich e ho notato che l'autore utilizza le estensioni di classe per contenere callback delegati anziché farli gestire nella classe stessa, ad esempio:

delegare callback all'interno dell'estensione di classe:

extension LogsViewController : UIPopoverPresentationControllerDelegate {
    func adaptivePresentationStyleForPresentationController(controller: UIPresentationController, traitCollection: UITraitCollection) -> UIModalPresentationStyle {
        ...
    }
}

al contrario di averlo contenuto nella classe:

delegare callback all'interno della classe:

class LogsViewController : UITableViewController, UIPopoverPresentationControllerDelegate {
    func adaptivePresentationStyleForPresentationController(controller: UIPresentationController, traitCollection: UITraitCollection) -> UIModalPresentationStyle {
        ...
    }
}

L'ho trovato strano e interessante allo stesso tempo. Ha un file dedicato solo alle estensioni della classe LogsViewController denominato "LogsViewControllerExtension.swift" e ha un'estensione diversa per ciascun protocollo delegato: UITableViewDataSource, UISplitViewDelegate, ecc.

più estensioni di classe ciascuna con callback delegati all'interno del proprio file:

extension LogsViewController: UISplitViewControllerDelegate {
    ... callbacks
}

extension LogsViewController : UIPopoverPresentationControllerDelegate {
    ... callbacks
}

Perché?

Quali vantaggi ci sono nel fare questo? Posso vedere dove potrebbe essere un po 'più leggibile separarlo ma allo stesso tempo è un livello di indiretta. Ci sono principi di OO che supportano o non fanno questo?


1
Puoi scrivere un sacco di strutture come questa che sono fondamentalmente supportate dai principi OO ma che sono ancora colpevoli di ingegnerizzazione eccessiva.
Robert Harvey,

1
@RobertHarvey vero, ma stai insinuando che il codice di esempio che ho mostrato qui è una forma di ingegnerizzazione eccessiva? La delega è un modello comune nello sviluppo di iOS. Inoltre, se usi le estensioni di classe o meno, non cambi il codice al suo interno, quindi sarebbe più simile alla ristrutturazione del codice piuttosto che al re (/ over) -ingegneria
morbidhawk

1
Sto vedendo questo schema di lancio di un sacco di estensioni nello stesso file e non so da dove provenga. Sembra che alcune persone lo stiano già abusando e lanciando arbitrariamente ogni piccola parte di codice in un'estensione all'interno dello stesso file. Sono sicuro che ci sia una buona ragione per farlo a volte, ma ho l'impressione che alcuni programmatori lo stiano facendo senza capire il perché. Continuo a cercare un vantaggio rispetto a MARK: - e mi piacerebbe trovare una fonte definitiva sul perché le estensioni dovrebbero essere utilizzate in questo modo.
David Lari,

Risposte:


15

Non so perché hai detto che aggiunge un livello di riferimento indiretto. Forse vuoi dire qualcosa di diverso da quello rispetto al significato tradizionale, perché non esiste alcuna indiretta aggiuntiva creata facendo questo. Ma perché farlo?

Lo faccio perché è più modulare. Tutto il codice richiesto dall'interfaccia è raggruppato in un unico posto (tranne le proprietà effettive.) Se in seguito scelgo di creare una classe separata per implementare quel protocollo (e quindi introdurre un livello effettivo di indiretto), tutto ciò di cui ho bisogno fare è cambiare l'estensione in una classe a sé stante (passando le proprietà necessarie attraverso una funzione init) e creare una proprietà su ViewController per creare un'istanza dell'oggetto.

Ho anche inserito tutte le funzioni private che sono utilizzate solo dalle funzioni di quel protocollo nell'estensione. Non sono arrivato al punto di creare un file completamente separato per l'estensione, ma farlo chiarisce che quelle funzioni private sono solo per quel protocollo.

E in ogni caso, le persone spesso si lamentano dei fat view controller e rompere un controller di visualizzazione in questo modo aiuta a mantenerlo meglio organizzato, anche se in realtà non rende il controller di vista più sottile.


Capisco cosa intendi per modularità. Una volta capito cosa stava succedendo, sembrava un modo pulito di separare le preoccupazioni. Il livello di riferimento indiretto penso sia per una nuova serie di occhi (e sono di parte proveniente dal modo Obj-c). Sento lo stesso livello di riferimento indiretto quando si esegue la sottoclasse in cui si fa riferimento al codice che è definito da qualche altra parte nella classe base ed è un po 'più difficile trovarlo. Sono d'accordo che organizzativamente aggiunge un vantaggio (con un piccolo costo di riferimento)
morbidhawk,

Immagino che ciò sia già stato fatto in precedenza con le categorie in Obj-C. Non sono mai stato un grande fan di quelli, ma penso che abbiano richiesto un file separato. Da ora in Swift puoi mantenere l'estensione nello stesso file, è quello che probabilmente farò se decido di romperli in quel modo
morbidhawk,

2

Come ha detto Daniel in merito all'indirizzamento indiretto, non esiste alcun livello.
Sono d'accordo e vorrei aggiungere una funzionalità extra potente delle estensioni di protocollo che conoscevo di recente.

Supponi di avere un protocollo, didCopyTextad esempio. Lo implementerai come:

protocol didCopyText {
  var charachtersCount: Int {get}
  func addToClipboardWith(text: String)
}

In Swift, proprietà e metodi non sono implementati nella dichiarazione del Protocollo, si vorrebbe scrivere l'implementazione in ogni classe conforme a didCopyText, con un numero incrementale di classi conformi a questo protocollo con la stessa implementazione, finirebbe con un semplice disordine codice ripetuto. Ecco dove le estensioni di protocollo sono utili.

protocol didCopyText {
var charachtersCount: Int {
    get {
     // implementation
    }
}
func addToClipboardWith(text: String) {
      // implementation
 }
}

Con l'implementazione delle proprietà e dei metodi del protocollo. Ora, qualsiasi classe conforme a questo protocollo, utilizzerà la stessa implementazione.


grazie per averlo condiviso. Al momento in cui ho posto questa domanda non mi ero reso conto di alcuni degli svantaggi dell'ereditarietà OO e quello che stai descrivendo qui è un ottimo modo per riutilizzare le stesse funzioni da tutte le classi di implementazione che si conformano a quell'interfaccia piuttosto che essere costrette a ereditare tutto da un oggetto. E se segui il principio di Segregazione dell'interfaccia puoi spezzare i protocolli secondo necessità per assicurarti che le classi di implementazione non abbiano mai proprietà / metodi dall'interfaccia di cui non hanno bisogno.
morbidhawk,

1

Supponiamo che la tua classe supporti tre protocolli e quindi devi aggiungere tre serie di funzioni. L'unico scopo di queste funzioni è supportare un protocollo, quindi è necessaria della documentazione.

Tuttavia, se si aggiunge un'estensione per ciascun protocollo e in ciascuna estensione si implementano esattamente le funzioni necessarie per quell'unico protocollo, ciò rende il codice molto più leggibile.

Molto probabilmente non li metterei in file separati a meno che queste estensioni non siano veramente grandi.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.