Por que razões você usaria uma extensão de classe separada para cada delegado no Swift?


13

Eu estava trabalhando em um tutorial de Ray Wenderlich e notei que o autor usa extensões de classe para reter delegados de retorno de chamada em vez de tê-los tratados na própria classe, ou seja:

delegar retornos de chamada dentro da extensão de classe:

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

em vez de contê-lo na classe:

delegar retornos de chamada dentro da classe:

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

Achei isso estranho e interessante ao mesmo tempo. Ele possui um arquivo dedicado apenas às extensões da classe LogsViewController denominada "LogsViewControllerExtension.swift" e possui uma extensão diferente para cada protocolo de delegado: UITableViewDataSource, UISplitViewDelegate, etc.

várias extensões de classe, cada uma com delegação de retorno de chamada em seu próprio arquivo:

extension LogsViewController: UISplitViewControllerDelegate {
    ... callbacks
}

extension LogsViewController : UIPopoverPresentationControllerDelegate {
    ... callbacks
}

Por quê?

Que vantagens existem para fazer isso? Eu posso ver onde pode ser um pouco mais legível separar isso, mas ao mesmo tempo é um nível de indireção. Existem princípios de OO que apoiam ou são contra isso?


1
Você pode escrever muita estrutura como essa, que é fundamentalmente suportada pelos princípios de OO, mas ainda assim é culpada de excesso de engenharia.
Robert Harvey

1
@RobertHarvey true, mas você está implicando que o código de exemplo que mostrei aqui é uma forma de superengenharia? Delegação é um padrão comum no desenvolvimento do iOS. Além disso, se você usar extensões de classe ou não, não alterar o código dentro dela, por isso seria mais como código de reestruturação ao invés de re (/ over) -Engenharia
morbidhawk

1
Estou vendo esse padrão de lançar várias extensões no mesmo arquivo e não sei de onde isso vem. Parece que algumas pessoas já estão abusando e jogando arbitrariamente cada pedacinho de código em uma extensão dentro do mesmo arquivo. Tenho certeza de que há uma boa razão para fazer isso de vez em quando, mas tenho a impressão de que alguns programadores estão fazendo isso sem entender o porquê. Eu continuo procurando uma vantagem disso sobre o uso de MARK: - e gostaria de encontrar alguma fonte definitiva sobre por que as extensões devem ser usadas dessa maneira.
David Lari 23/03

Respostas:


15

Não sei por que você disse que isso adiciona um nível de indireção. Talvez você queira dizer algo diferente do que o significado tradicional, porque não há indireção extra criada ao fazer isso. Mas por que fazer isso?

Eu faço isso porque é mais modular. Todo o código exigido pela interface é agrupado em um único local (exceto as propriedades reais.) Se, posteriormente, optar por criar uma classe separada para implementar esse protocolo (e assim introduzir um nível real de indireção), tudo o que preciso O fazer é alterar a extensão para uma classe própria (passando as propriedades necessárias por meio de uma função init) e criar uma propriedade no ViewController para instanciar o objeto.

Também coloquei quaisquer funções privadas que são usadas apenas pelas funções desse protocolo na extensão. Não fui tão longe a ponto de criar um arquivo completamente separado para a extensão, mas isso deixa claro que essas funções privadas são apenas para esse protocolo.

De qualquer forma, as pessoas costumam reclamar dos controladores de exibição de gordura e a quebra de um controlador de exibição dessa maneira ajuda a mantê-lo melhor organizado, mesmo que ele não torne o controlador de exibição mais fino.


Entendo o que você quer dizer com modularidade. Depois que eu entendi o que estava acontecendo, parecia uma maneira limpa de separar as preocupações. O nível de indireção que penso é para um novo par de olhos (e sou tendencioso vindo da maneira Obj-c). Sinto o mesmo nível de indireção ao subclassificar onde o código está sendo referenciado, definido em outro lugar na classe base e é um pouco mais difícil encontrá-lo. Concordo que organizacionalmente acrescenta benefício (com um pouco de custo indireto)
morbidhawk

Eu acho que isso já foi feito com categorias de classe no Obj-C. Eu nunca fui muito fã deles, mas acho que eles exigiram um arquivo separado. Desde agora em Swift você pode manter a extensão no mesmo arquivo que é o que eu provavelmente vou fazer se eu decidir rompê-los assim
morbidhawk

2

Como Daniel disse em relação à indireção, não há nível disso.
Eu concordo com ele e gostaria de adicionar um recurso extra poderoso das extensões de protocolo que eu conhecia recentemente.

Diga que você tem um protocolo, didCopyTextpor exemplo. Você implementará isso como:

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

No Swift, propriedades e métodos não são implementados na declaração do protocolo, você deseja escrever a implementação em todas as classes em conformidade com a didCopyText, com um número incremental de classes em conformidade com este protocolo com a mesma implementação, isso acabaria com apenas uma confusão código repetido. É aí que as Extensões de Protocolo são úteis.

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

Com a implementação das propriedades e métodos do protocolo. Agora, qualquer classe que esteja em conformidade com este protocolo, usará a mesma implementação.


obrigado por compartilhar isso. No momento em que fiz essa pergunta, não percebi algumas das desvantagens da herança OO, e o que você está descrevendo aqui é uma ótima maneira de obter as mesmas funções reutilizadas por todas as classes de implementação que estão em conformidade com essa interface, em vez de serem forçadas a herdar tudo de um objeto. E se você seguir o princípio de Segregação da interface, poderá desmembrar os protocolos conforme necessário para garantir que as classes de implementação nunca tenham propriedades / métodos da interface de que não precisam.
morbidhawk

1

Digamos que sua classe suporte três protocolos e, portanto, você precisa adicionar três conjuntos de funções. O único objetivo dessas funções é oferecer suporte a um protocolo, portanto, você precisa de alguma documentação.

No entanto, se você adicionar uma extensão para cada protocolo e, em cada extensão, implementar exatamente as funções necessárias para esse protocolo, isso tornará seu código muito mais legível.

Eu provavelmente não os colocaria em arquivos separados, a menos que essas extensões sejam realmente grandes.

Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.