Modularidade e Reuso de Software
Refatoração do sistema e utilização de padrões e componentes
Iúri Ribeiro, Sérgio René { iara, srpvnf } at cin.ufpe.br
Índice
Refatoração do sistema...3
Extract method...3
Extract superclass + template method...20
Extract Interface...27 Componentes...31 Arquivo de propriedades...31 Bridge...32 Factory...34 Conclusão...36
Refatoração do sistema
Vários pontos do código com oportunidades de reuso e melhoria da modularidade analisados nas atividades anteriores foram, então, refatorados nesta atividade. As alterações feitas serão mostradas e explicadas abaixo. Todas as imagens mostradas serão na ordem: antes e depois da modificação, quando possível.
Extract method
Foi usado o comando de refatoração ‘extract method’ em vários casos. O objetivo foi separar trechos de códigos com responsabilidades diferentes (quando possível). Outro objetivo é possibilitar o reuso dos métodos, o que acontece em alguns casos.
buscarLinhasPesquisa. A parte do método responsável pela leitura do banco de dados e criação da ‘LinhaPesquisa’ foi separada em outro método: ‘readLinhaPesquisa’.
buscarPublicacao. Semelhante ao anterior. Foi criado um método para a leitura e criação da entidade básica ‘Publicacao’.
buscarMembro. Semelhante ao anterior.
cadastrarLinhaPesquisa. Semelhante ao anterior, porém o trecho que foi separado deste método diz respeito ao set dos atributos para o cadastro. Além disso, neste caso, foi adicionado um método de cadastro de dados específicos, no caso o trecho de código que engloba ‘cadastrarMembros’ e ‘cadastrarPublicacoes’.
editarLinhaPesquisa. Semelhante ao anterior.
eInvalido. Neste caso, foi criado um método com a validação de string quanto à valores nulos ou vazios: ‘stringNullOuEmpty’.
isMembroInvalido. Semelhante ao anterior. Reusado o método da modificação anterior.
gerarPublicacaoBibTex. Este método possuía um grande número de linhas de código (LOC). Foi criado um método, então, para englobar a regra de cada tipo diferente de publicação. Os métodos com as regras são idênticos à como eram antes da refatoração.
Métodos gerados do gerarPublicacaoBibTex. Após o refactoring acima, foi criado um método appendStrings para reutilizar a concatenação de strings, como também adicionar uma nova linha no final (“\n”). Dessa forma foi reduzida em mais de metade o número de linhas de código. Após isso, ainda foi identificado que parte dos métodos são idênticos (parte com autor e título). Esta parte então foi extraída para um novo método, e reusado em todos os outros métodos.
finalizarConexao. Este método foi criado para ser reutilizado em todos os locais onde o closeConnection era chamado. Tanto dando commit na transação, ou não. Essas chamadas eram repetidas em demasia na fachada.
Extract superclass + template method
ServletDoPostCallDoGet. Várias classes do tipo Servlet possuíam métodos iguais ou bastante similares. Foi criado, então, uma superclasse para combinar tais códigos semelhantes nessa classe.
CadastrarPublicacao2 e EditarPublicacao2Servlet. As duas classes possuíam a mesma implementação do único método ‘doGet’. Então foi extraída uma superclasse
(nomeada de CadastrarPublicacaoServlet) para ter a implementação deste método e as duas classes estenderem tal superclasse. A única parte em que eles se diferenciam é na chamada do método da fachada, por isso foi criado um método abstrato na classe pai ‘AcaoFachada’ para os outros especificarem qual ação tomar.
EditarPublicacaoServlet e CadastrarPublicacaoServlet. Semelhante ao anterior. A única diferença da implementação das duas classes está na string utilizada pro ‘jsp’. Então, colocamos na superclasse um método abstrato para retornar a string com o nome do jsp.
m
CadastroMembroServlet e EditarMembroServlet. Semelhante ao anterior, porém neste caso a mudança está em relação ao método chamado da fachada. Então criamos na superclasse um método abstrato para ser implementada a ação correspondente à chamada da fachada.
Extract Interface
Será utilizado o extract interface quando for feito o padrão bridge para os drivers de conexão, mostrado posteriormente neste documento. Consiste em criar uma interface com determinados métodos para diminuir a dependência entre classes. O objetivo no caso do bridge é exatamente este, como também dar flexibilidade para a utilização de outros diferentes drivers sem impacto maior no sistema.
A. Outros
membroAux. O código possuía grande número de linhas de código. Isso aconteceu devido a uma forma ruim de capturar elementos do HttpServletRequest. Foi, então, modificado a forma de captura da maioria dos elementos possíveis. Apenas o
elemento ‘foto’ teve sua lógica mantida, pois havia uma validação sobre a extensão do arquivo (se é gif, jpg ou png).
publicacaoAux. Semelhante ao anterior. Neste caso que manteve a lógica foi o ‘pdf’, pois há lógica sobre a extensão do arquivo também (neste caso, se é pdf).
Componentes
Arquivo de propriedades
Foi criado um arquivo de propriedades para conter informações importantes sobre o computador que está rodando o sistema. O arquivo de propriedades é um txt e está mostrado abaixo. Informações como o tipo de banco de dados, o diretório do sistema, usuário e senha, servidor e o nome do banco de dados a ser acessado estão no arquivo de propriedades. O objetivo é deixar o sistema flexível a novos parâmetros de configuração que possam ser modificados sem recompilar o sistema, além de poder ser modificado em tempo de execução, caso necessário.
Para isso é necessário uma classe específica para ler o arquivo de configurações. A classe responsável por isso está mostrada abaixo.
Esse arquivo de configuração será usado, por exemplo, na fachada para saber qual conexão criar com o banco de dados. Dependendo do tipo do banco de dados o código pode ser diferente. Além disso, ainda temos o usuário e senha como também o nome do banco de dados e o servidor, que são parâmetros necessários para criação da conexão e estão presentes no arquivo de configuração.
Bridge
Foi utilizado o padrão bridge para dar flexibilidade e suporte ao driver de conexão ao banco utilizado. Para isso foi criado uma interface em que cada driver utilizado deve implementar (no caso apenas JDBCConnection). Foi criado a interface ConexaoDados mostrada abaixo.
Com isso, temos de ajustar a classe JDBCConnection atualmente utilizada para este novo padrão, ou seja, temos que fazer com que a classe implemente a interface criada. As figuras abaixo mostram o antes e o depois.
Após essa modificação, temos de ajustar a Fachada para utilizar o novo padrão bridge, ou seja, utilizar a interface ConexaoDados. O tipo da conexão foi modificado para ConexaoDados.
Factory
Foi criado um factory para a criação dos controladores. O objetivo é diminuir a dependência direta para as classes dos controladores. As figuras de como ficou a classe factory dos controladores como também a classe controlador estão abaixo.
Com isso, temos de mudar os lugares que criam os controladores. Um exemplo está abaixo no cadastrarMembro e no buscarMembro.
Conclusão
Depois das atividades anteriores, pudemos identificar oportunidades de reuso de código como também oportunidades na melhoria de modularidade e ajeitar o código quanto a esses pontos, além de adotar padrões e componentes. Bastantes mudanças foram feitas para corrigir ou ajustar tais oportunidades descobertas. Algumas das análises feitas anteriormente estão abaixo. Elas mostram que conseguimos atingir o objetivo: diminuímos alguns métodos que possuíam grande LOC, melhoramos o reuso de código, melhoramos a modularidade diminuindo o acoplamento e a dependência entre as classes e os pacotes. Além disso, vale ressaltar, ainda implementamos alguns padrões de projeto, como também componentes, para melhorar pontos como a flexibilidade e a melhor abstração de algumas partes do código.
Um exemplo da melhoria no acoplamento das classes e pacotes foi que os pacotes ficaram menos acoplados um com os outros. Como é possível ver a partir da matriz de acoplamento:
Antes:
Nessa visão, conseguimos ver como os pacotes se acoplam e a intensidade, notamos que a view está acoplada com logic (fachada) e a fachada com controladores. O que é normal, visto que os servlets sempre chamam algo da fachada e a fachada repassa para os controladores. Antes:
Nessa visão conseguimos observar como está o tamanho das classes e a hieraquia delas. Vemos que os servlets agora tem mais níveis de herança agrupando em uma superclasse funções comuns.
Antes: