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!
The examples made everything clear. Check Your Eligibility for Ehsaas Program 8171 Thanks for that!
Post a Comment
2 comments :
Check out the Jackpot 6000 slot game on brand new site in Poland that offers you freespins!
The examples made everything clear. Check Your Eligibility for Ehsaas Program 8171 Thanks for that!
Post a Comment