Vocabulário do Kotlin: Delegates
Uma das formas de executar um trabalho é delegar esse trabalho a outra parte. Não estou falando sobre delegar seu trabalho para um amigo, mas sim de delegar trabalho de um objeto para outro.
E a delegação não é uma novidade na área do software. A delegação é um padrão de design no qual um objeto lida com uma solicitação delegando-a a um objeto auxiliar, conhecido como delegate. O delegate é responsável por lidar com a solicitação em nome do objeto original e por disponibilizar os resultados ao objeto original.
O Kotlin facilita a delegação fornecendo suporte a delegates de classe e propriedade e até mesmo contendo alguns delegates integrados próprios.
Digamos que você tenha um caso de uso para um ArrayList que possa recuperar seu último item removido. Basicamente, tudo o que você precisa é da mesma funcionalidade ArrayList com uma referência ao último item removido.
Uma forma de fazer isso é estender a classe ArrayList. Como essa nova classe está estendendo o ArrayList concreto, não implementando a interface MutableList, ela está altamente vinculada à implementação do ArrayList concreto.
Não seria legal poder substituir a função remove() para manter uma referência do item excluído e delegar o restante das implementações vazias de MutableList para outro objeto? O Kotlin oferece uma forma de fazer isso delegando a maior parte do trabalho para uma instância interna de ArrayList e personalizando seu comportamento. Para isso, o Kotlin introduz uma nova palavra-chave: by.
Vejamos como funciona a delegação de classes. Quando você usa a palavra-chave by, o Kotlin automaticamente gera o código para usar a instância de innerList como um delegate.
A palavra-chave by instrui o Kotlin a delegar a funcionalidade da interface MutableList para uma instância interna de ArrayList, chamada innerList. O ListWithTrash ainda dá suporte a todas as funções da interface MutableList fornecendo métodos de ligação direta com o objeto ArrayList interno. E, agora, você tem a capacidade de adicionar seu próprio comportamento.
Vamos ver como isso funciona. Se você analisar o código Java descompilado do código de byte ListWithTrash, verá que o compilador do Kotlin na verdade cria funções wrapper que chamam as funções correspondentes do objeto ArrayList interno.
Observação: o compilador do Kotlin usa outro padrão de design chamado Padrão decorator, para dar suporte à delegação de classes no código gerado. No padrão decorator, a classe decorator compartilha a mesma interface com a classe a ser decorada. A classe decorator mantém uma referência interna da classe de destino e agrupa, ou decora, todos os métodos públicos fornecidos com a interface.
Os delegates são especialmente úteis quando não é possível herdar de uma determinada classe. Com a delegação de classes, a classe não faz parte de nenhuma hierarquia. Em vez disso, ela compartilha a mesma interface e decora o objeto interno do tipo original. Isso significa facilidade para trocar a implementação sem danificar a API pública.
Além da delegação de classes, também é possível usar a palavra-chave by para delegar propriedades. Com a delegação de propriedades, o delegate é responsável por lidar com as chamadas às funções get e set da propriedade. Isso pode ser extremamente útil se for preciso reutilizar a lógica getter/setter em outros objetos, além de permitir estender facilmente a funcionalidade além dos campos auxiliares simples.
Vamos supor que você tenha uma classe Person definida da seguinte maneira:
class Person(var name: String, var lastname: String)
A propriedade name dessa classe tem alguns requisitos de formatação. Quando name é definida, convém garantir que a primeira letra seja capitalizada, deixando o restante em letras minúsculas. Além disso, na atualização de name, convém incrementar automaticamente a propriedade update count.
Você poderia implementar essa funcionalidade da seguinte maneira:
Embora isso funcione, e se os requisitos mudarem e você também quiser incrementar updateCount sempre que lastname mudar? Você poderia copiar/colar a lógica para escrever um setter personalizado, mas acabaria escrevendo exatamente o mesmo setter para cada propriedade:
Os dois métodos setter são quase idênticos, o que é uma indicação de que um deles não deveria existir. Com a delegação de propriedades, é possível reutilizar o código delegando getters e setters a uma propriedade.
Assim como na delegação de classes, você pode usar a palavra-chave by para delegar uma propriedade, e o Kotlin gerará o código para usar o delegate quando a sintaxe property for utilizada.
Com essa mudança, você delegou as propriedades name e lastname à classe FormatDelegate. Agora, vamos analisar o código para FormatDelegate. A classe delegate precisa implementar ReadProperty<Any?, String> se você precisar delegar apenas o getter, ou ReadWriteProperty<Any?, String> se você precisar delegar o getter e o setter. Em nosso caso, FormatDelegate precisa implementar ReadWriteProperty<Any?, String>, uma vez que queremos fazer a formatação quando o setter for invocado.
Você deve ter notado que há dois parâmetros adicionais nas funções getter e setter. O primeiro é thisRef, e ele representa o objeto que contém a propriedade. thisRef pode ser usado para acessar o próprio objeto para fins como verificar outras propriedades ou chamar outras funções de classe. O segundo parâmetro é KProperty<*>, que pode ser usado para acessar metadados na propriedade delegada.
Voltando ao requisito, vamos usar thisRef para acessar e incrementar a propriedade updateCount.
Para entender como isso funciona, vamos analisar o código Java descompilado. O compilador do Kotlin gera o código para manter referências privadas do objeto FormatDelegate para as propriedades name e lastname, juntamente com getters/setters que contêm a lógica adicionada.
O compilador também cria uma KProperty[] para armazenar as propriedades delegadas. Se você analisar os getters e setters gerados para a propriedade name, a instância é armazenada no índice 0, ao passo que a propriedade lastname é armazenada no índice 1.
Com esse truque, qualquer autor da chamada pode acessar a propriedade delegada com a sintaxe regular da propriedade.
person.lastname = “Smith” // calls generated setter, increments count
println(“Update count is $person.count”)
O Kotlin não apenas dá suporte aos delegates, como também fornece delegates integrados na biblioteca padrão do Kotlin, algo que veremos em mais detalhes em outro artigo.
Os delegates podem ajudar a delegar tarefas para outros objetos e a reutilizar melhor o código. O compilador do Kotlin cria o código para permitir o uso otimizado dos delegates. O Kotlin usa uma sintaxe simples com a palavra-chave by para delegar uma propriedade ou classe. Nos bastidores, o compilador do Kotlin gera todo o código necessário para dar suporte à delegação sem expor nenhuma mudança à API pública. Basicamente, o Kotlin gera e mantém todo o código boilerplate necessário para os delegates. Ou, em outras palavras, é possível delegar delegates para o Kotlin.
Check out the Jackpot 6000 slot game on brand new site in Poland that offers you freespins!
Postar um comentário
Um comentário :
Check out the Jackpot 6000 slot game on brand new site in Poland that offers you freespins!
Postar um comentário