Refatoração de Código: Limitar Instanciação Com Singleton

Investir em Você é Barra de Ouro a R$ 2,00. Cadastre-se e receba grátis conteúdos Android sem precedentes! Você receberá um email de confirmação. Somente depois de confirma-lo é que eu poderei lhe enviar os conteúdos semanais exclusivos. Os artigos em PDF são entregues somente para os inscritos na lista.

Email inválido.
Blog /Android /Refatoração de Código: Limitar Instanciação Com Singleton

Refatoração de Código: Limitar Instanciação Com Singleton

Vinícius Thiengo
(2021)
Go-ahead
"O método consciente de tentativa e erro é mais bem-sucedido que o planejamento de um gênio isolado."
Peter Skillman
Prototipagem Android
Capa do curso Prototipagem Profissional de Aplicativos
TítuloAndroid: Prototipagem Profissional de Aplicativos
CategoriasAndroid, Design, Protótipo
AutorVinícius Thiengo
Vídeo aulas186
Tempo15 horas
ExercíciosSim
CertificadoSim
Acessar Curso
Quer aprender a programar para Android? Acesse abaixo o curso gratuito no Blog.
Lendo
TítuloManual de DevOps: como obter agilidade, confiabilidade e segurança em organizações tecnológicas
CategoriaEngenharia de Software
Autor(es)Gene Kim, Jez Humble, John Willis, Patrick Debois
EditoraAlta Books
Edição1ª
Ano2018
Páginas464
Conteúdo Exclusivo
Investir em Você é Barra de Ouro a R$ 2,00. Cadastre-se e receba gratuitamente conteúdos Android sem precedentes!
Email inválido

Tudo bem?

Neste artigo continuamos com a série Refatoração de Código para desenvolvimento de softwares com maior desempenho.

Desta vez vamos falar sobre o velho e conhecido padrão de projeto Singleton, mais precisamente do método de refatoração Limitar Instanciação com Singleton.

Esse método de refatoração vai nos ajudar a colocar o Singleton em nossos algoritmos quando enxergada a oportunidade de melhorar o código com esse padrão.

Lembrando que todos os artigos dessa série, incluindo os de padrões de projeto, podem ser utilizados para estudos e melhorias de qualquer projeto de software orientado a objetos.

Antes de prosseguir com conteúdo do método proposto aqui, é importante que você saiba o que é e como utilizar o padrão de projeto Singleton além de conhecer também o método de refatoração Substituir Construtores Por Métodos de Criação.

Abaixo os links dos artigos daqui do Blog sobre esses assuntos:

Antes de prosseguir, não esqueça de se inscrever na ðŸ“« lista de e-mails do Blog para receber em primeira mão todos os conteúdos exclusivos sobre desenvolvimento e codificação limpa.

A seguir os tópicos que estaremos abordando em artigo:

Motivação

O código está apresentando problemas de desempenho, um medidor de desempenho informa sobre um gargalo na criação de várias instâncias.

Debugando o código você percebe que uma classe que não nunca tem o estado alterado durante a execução está sendo instanciada várias vezes, onde apenas uma instância dela, em todo o código, seria o suficiente.

Obviamente que pode haver ainda outros problemas, mas esse é evidente, ao menos, um consumo desnecessário de memória.

Assim você decide implementar o Singleton nessa classe.

Código de exemplo

O script de exemplo é parte de um sistema de permissões de acesso.

Esse sistema tem até seis classes de permissão e todas elas têm a mesma interface e também herdam da mesma superclasse e, o principal (o que realmente indica uma refatoração para um Singleton), elas não têm mudança de estado e são instanciadas frequentemente no código.

Vamos seguir a refatoração utilizando uma classe desse conjunto de seis.

Pois devido as características citadas anteriormente (mesma interface e não alteração de estado) seria apenas repetição nas outras classes a aplicação da refatoração Limitar Instanciação com Singleton.

Logo, segue código da classe PermissaoRequisitada, uma das seis classes:

public class PermissaoRequisitada extends Permissao {

public static final String NOME = "REQUISITADA";

public String nome(){
return NOME;
}

public void reivindicadoPor(
SistemaAdmin admin,
SistemaPermissao permissao ){

permissao.vaiSerAministradoPor( admin );
permissao.setEstado( permissao );
}
}

 

Agora podemos seguir com a mecânica de refatoração.

Mecânica

Nosso primeiro passo é identificar nossa classe que está sendo instanciada várias vezes e não apresenta mudança de estado (atributo) ou o estado dela é compartilhado.

Já sabemos que são seis classes (aqui vamos refatorar somente uma como suficiente para entendimento do método de refatoração).

Mas espere ai, você não falou sobre estado compartilhado?

Estado compartilhado é muitas vezes aplicado via atributo estático, onde todas as instâncias da classe têm exatamente o mesmo valor, para atributos estáticos.

A outra forma é por meio de injeção de dependência, a grosso modo, por meio de parâmetros de métodos ou construtores das classes, onde os parâmetros sendo utilizados em uma instância são os mesmos sendo utilizados em outras instâncias.

Resumo: os valores sendo utilizados nos atributos das instâncias, seguindo os contextos indicados anteriormente, esses são valores compartilhados, estados compartilhados.

Note que no método reivindicadoPor() da classe PermissaoRequisitada há objetos sendo injetados na instância, injetados como parâmetros de entrada.

Como esses estão entrando no objeto do tipo PermissaoRequisitada e não sendo instanciados dentro dele e juntando a isso o conhecimento de que as classes irmãs de PermissaoRequisitada e a própria nunca têm estado alterado depois de vinculado os valores de parâmetros de entrada.

Sabendo disso podemos concluir que qualquer instância de PermissaoRequisitada ou de suas classes irmãs compartilham os mesmos valores de atributos, depois desses inicializados.

Ainda no primeiro passo, devemos, na classe identificada, aplicar o método de refatoração Substituir Construtores por Métodos de Criação.

Mesmo quando tem somente um único construtor e esse sendo o construtor padrão da linguagem.

Logo depois desse primeiro passo temos o seguinte novo código em PermissaoRequisitada:

public class PermissaoRequisitada {
...

public static Permissao instancia(){
return new PermissaoRequisitada();
}
...
}

 

Ok, mas por que retornar um tipo Permissao no método de criação?

Nesse caso, em especifico, porque são seis classes na mesma hierarquia com a classe Permissao sendo a superclasse, e todas essas classes representam estados de outros objetos.

Logo, para não ter de trabalhar com variáveis de cada um dos seis tipos nesses objetos clientes, utilizamos apenas o tipo Permissao que nos permite manter as particularidades de cada classe de estado.

Porém sem a sobrecarga de varáveis especificas do tipo Permissao, somente uma do tipo Permissao é utilizada.

Ainda no primeiro passo temos de substituir as chamadas a instanciação de nossa classe PermissaoRequisitada pela chamada ao método criador, getInstance().

Isso nos códigos clientes.

Segue exemplo de um desses algoritmos cliente:

public class SistemaPermissao {

private Permissao estado;
...

public SistemaPermissao(
SistemaUsuario requisitor,
SistemaPerfil perfil ){

this.requisitor = requisitor;
this.perfil = perfil;
/* state = new PermissaoRequisitada() */
state = PermissaoRequisitada.instancia();
...
}
...
}

 

Nosso segundo passo é criar um atributo singleton, ele será estático, privado, do mesmo tipo da classe e já na declaração dessa variável podemos atribuir uma instância.

Mas em nosso caso vamos evitar essa última estratégia.

Então temos:

public class PermissaoRequisitada {
private static Permissao state;
...
}

 

Nosso terceiro e último passo é fazer com que nosso método de criação, getInstance(), retorne nosso atributo singleton.

Logo, temos:

public class PermissaoRequisitada {
...

public static Permissao instancia(){

if( state == null ){
state = new PermissaoRequisitada();
}

return state;
}
...
}

 

Se em seu caso for necessário algum parâmetro, pode colocá-lo como parâmetro de entrada em seu método de criação, não há problemas quanto aos passos do método de refatoração ao fazer isso em seu código.

Abaixo a classe atualizada:

public class PermissaoRequisitada {

public static final String NOME = "REQUISITADA";

private static Permissao state;

public static Permissao instancia(){

if( state == null ){
state = new PermissaoRequisitada();
}

return state;
}

public String nome(){
return NOME;
}

public void reivindicadoPor(
SistemaAdmin admin,
SistemaPermissao permissao ){

permissao.vaiSerAministradoPor( admin );
permissao.setEstado( permissao );
}
}

 

O que deveríamos fazer agora, se estivéssemos com o projeto real em mãos, seria atualizar todas as outras classes de estado de permissão para se tornarem classes Singletons.

Um passo extra e que considero muito importante é não permitir instanciações externas da classe recapturada para um Singleton.

No caso de PermissaoRequisitada e das classes irmãs dela isso ainda é possível.

Para esse passo extra apenas vamos adicionar um construtor com modificador de acesso private, isso na classe PermissaoRequisitada.

Assim, temos:

public class PermissaoRequisitada extends Permissao {
...

private Permissao(){
super();
}
...
}

 

Com era o construtor padrão do Java que estava sendo utilizado, sabemos que somente o super() já atende como conteúdo do construtor, agora private.

Assim somente a instanciação em getInstance() é que funcionará.

Recomendo que aplique esse passo extra em todas as refatorações Limitar Instanciação com Singleton.

instance e getInstance():

Esse nomes não foram adotados aleatoriamente.

Quando trabalhando com padrões de projeto, nomes de classes, métodos e variáveis podem seguir uma convenção onde qualquer outro programador somente de visualizar a convenção sendo aplicada saberá o tipo de padrão sendo utilizado e consequentemente o modelo de código.

Isso é a linguagem universal aplicada pelos padrões de projeto sendo apresentada.

A variável de valor único de instancia em um Singleton e o método de retorno dela, quase sempre, recebem respectivamente os nomes: instance e getInstance()Mesmo em códigos não em inglês.

Dessa forma terminamos com o método de refatoração proposto aqui.

Conclusão

Apesar de muitos críticos ao uso do Singleton, ele tem suas qualidades.

Algumas vezes não precisamos de um medidor de desempenho para enxergar problemas no código.

Visto que uma classe está sendo utilizada em vários pontos do projeto, porém sempre com o mesmo estado, Singleton nela!

A melhora pode não ser visível, mas sabemos o problema que pode ocorrer caso uma refatoração não seja aplicada ao código.

O principal problema pode ser com a memória do sistema.

Então é isso.

Por fim, não deixe de se inscrever na 📩 lista de e-mails do Blog para receber os conteúdos de desenvolvimento e codificação limpa exclusivos, em primeira mão e também...

... na versão em PDF (versão liberada somente para os inscritos da lista de e-mails).

Abraço.

Outros artigos da série

Segue abaixo, lista de todos os artigos de refatoração de código presentes no Blog:

Fontes

Refatoração para Padrões

Use a Cabeça! Padrões de Projetos

Investir em Você é Barra de Ouro a R$ 2,00. Cadastre-se e receba grátis conteúdos Android sem precedentes!
Email inválido

Relacionado

Padrões de Implementação - Um Catálogo de Padrões Indispensável Para o Dia a Dia do ProgramadorPadrões de Implementação - Um Catálogo de Padrões Indispensável Para o Dia a Dia do ProgramadorLivros
Refatoração Para PadrõesRefatoração Para PadrõesLivros
Facebook Login, Firebase Android - Parte 5Facebook Login, Firebase Android - Parte 5Android
Google SignIn API, Firebase Android - Parte 6Google SignIn API, Firebase Android - Parte 6Android

Compartilhar

Comentários Facebook

Comentários Blog

Para código / script, coloque entre [code] e [/code] para receber marcação especifica.
Forneça seu nome válido.
Forneça seu email válido.
Forneça o comentário.
Enviando, aguarde...