¿Por qué razones usaría una extensión de clase separada para cada delegado en Swift?

13

Estaba trabajando en un tutorial de Ray Wenderlich y noté que el autor usa extensiones de clase para retener las devoluciones de llamadas de los delegados en lugar de hacer que se manejen en la clase misma, es decir:

delegar devoluciones de llamada dentro de la extensión de clase:

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

en lugar de tenerlo dentro de la clase:

delegar devoluciones de llamada dentro de la clase:

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

Esto me pareció extraño e interesante al mismo tiempo. Tiene un archivo dedicado solo a extensiones en la clase LogsViewController llamado "LogsViewControllerExtension.swift" y tiene una extensión diferente para cada protocolo de delegado: UITableViewDataSource, UISplitViewDelegate, etc.

múltiples extensiones de clase cada una con devoluciones de llamada delegadas dentro de su propio archivo:

extension LogsViewController: UISplitViewControllerDelegate {
    ... callbacks
}

extension LogsViewController : UIPopoverPresentationControllerDelegate {
    ... callbacks
}

¿Por qué?

¿Qué ventajas hay para hacer esto? Puedo ver dónde podría ser un poco más legible separar esto, pero al mismo tiempo es un nivel de indirección. ¿Hay principios OO que apoyan o no lo hacen?

morbidhawk
fuente
1
Puede escribir muchas estructuras como esta que están respaldadas fundamentalmente por los principios OO pero que aún son culpables de la ingeniería excesiva.
Robert Harvey, el
1
@RobertHarvey es cierto, pero ¿estás insinuando que el código de ejemplo que he mostrado aquí es una forma de ingeniería excesiva? La delegación es un patrón común en el desarrollo de iOS. Además, si usa extensiones de clase o no, no cambia el código dentro de él, por lo que sería más como la reestructuración del código en lugar de la re (/ over) -ingeniería
morbidhawk 03 de
1
Estoy viendo este patrón de lanzar un montón de extensiones en el mismo archivo, y no sé de dónde viene esto. Parece que algunas personas ya lo están abusando y simplemente están arrojando arbitrariamente cada pequeño código en una extensión dentro del mismo archivo. Estoy seguro de que hay una buena razón para hacerlo ocasionalmente, pero tengo la impresión de que algunos programadores lo están haciendo sin entender por qué. Sigo buscando una ventaja de esto sobre el uso de MARK: - y me encantaría encontrar una fuente definitiva sobre por qué las extensiones deben usarse de esta manera.
David Lari

Respuestas:

15

No sé por qué dijiste que agrega un nivel de indirección. Tal vez te refieres a algo diferente al significado tradicional, porque no hay una indirecta adicional creada al hacer esto. ¿Pero por qué hacerlo?

Lo hago porque es más modular. Todo el código que requiere la interfaz se agrupa en un solo lugar (excepto las propiedades reales). Si luego elijo hacer una clase separada para implementar ese protocolo (y así introducir un nivel real de indirección), todo lo que necesito para do es cambiar la extensión a una clase propia (pasando las propiedades necesarias a través de una función init) y crear una propiedad en el ViewController para instanciar el objeto.

También pongo las funciones privadas que solo son utilizadas por las funciones de ese protocolo en la extensión. No he ido tan lejos como para crear un archivo completamente separado para la extensión, pero al hacerlo deja en claro que esas funciones privadas son solo para ese protocolo.

Y, en cualquier caso, las personas a menudo se quejan de los controladores de vista gordos y romper un controlador de vista de esta manera ayuda a mantenerlo mejor organizado, incluso si en realidad no hace que el controlador de vista sea más delgado.

Daniel T.
fuente
Veo lo que quieres decir con modularidad. Una vez que entendí lo que estaba sucediendo, parecía una forma limpia de separar las preocupaciones. El nivel de indirección creo que es para un nuevo conjunto de ojos (y estoy sesgado viniendo del modo Obj-c). Siento el mismo nivel de indirección cuando subclasifico donde se hace referencia al código que se define en otro lugar de la clase base y es un poco más difícil de encontrar. Estoy de acuerdo en que organizacionalmente agrega beneficios (con un pequeño costo indirecto)
morbidhawk
Supongo que esto se ha hecho antes con categorías de clase en Obj-C. Nunca fui un gran admirador de ellos, pero creo que requirieron un archivo separado. Dado que ahora en Swift puedes mantener la extensión en el mismo archivo, eso es lo que probablemente haré si decido separarlos así
morbidhawk
2

Como dijo Daniel con respecto a la indirección, no hay un nivel de ello.
Estoy de acuerdo con él y me gustaría agregar una característica extra potente de Extensiones de Protocolo que conocí recientemente.

Digamos que tienes un protocolo, didCopyTextpor ejemplo. Lo implementará como:

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

En Swift, las propiedades y los métodos no se implementan en la declaración del Protocolo, es recomendable que escriba la implementación en cada clase conforme a didCopyText, con un número incremental de clases que se ajustan a este protocolo con la misma implementación, terminaría con solo un desorden código repetido Ahí es donde las Extensiones de protocolo son útiles.

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

Con la implementación de las propiedades y métodos del protocolo. Ahora, cualquier clase que cumpla con este protocolo, usará la misma implementación.

Mennabah
fuente
Gracias por compartir esto. En el momento en que hice esta pregunta, no me di cuenta de algunos de los inconvenientes de la herencia OO, y lo que está describiendo aquí es una excelente manera de reutilizar las mismas funciones en todas las clases de implementación que se ajustan a esa interfaz en lugar de verse obligados a heredar todo de un objeto. Y si sigue el principio de segregación de interfaz, puede separar los protocolos según sea necesario para garantizar que las clases de implementación nunca tengan propiedades / métodos de la interfaz que no necesitan.
morbidhawk
1

Digamos que su clase admite tres protocolos y, por lo tanto, debe agregar tres conjuntos de funciones. El único propósito de estas funciones es admitir un protocolo, por lo que necesita documentación.

Sin embargo, si agrega una extensión para cada protocolo, y en cada extensión implementa exactamente las funciones necesarias para ese protocolo, eso hace que su código sea mucho más legible.

Lo más probable es que no los coloque en archivos separados a menos que estas extensiones sean realmente grandes.

gnasher729
fuente