EM DESENVOLVIMENTO 🧑🔧
O objetivo do projeto é implementar melhorias em um sistema de folha de pagamento desenvolvido da AB1.
Primeiramente, vamos navegar pelo sistema anterior, classe por classe, a fim de identificar os code smells presentes no código.
Code smells procurados |
---|
Duplicated Code |
Long Parameter List |
Long Method |
Large Class |
Divergent Change |
Shotgun Surger |
Feature Envy |
Primitive Obsession |
Lazy Class |
Speculative Generality |
Message Chains |
Middle Man |
Indecent Exposure |
Data Class |
Refused Bequest |
Comments |
Os code smells identificados podem ser vistos aqui
-
Strategy
- Quando um novo empregado é adicionado, ele pode ser de 3 tipos, horista, assalariado ou comissionado. Para isso foi criado um método
add()
na classe principalEmployee
e um relacionamento hierárquico entre as subclassesHourly
,Comissioned
eAssalaried
. - Pôde ser observado 3 tipos de code smells ao fazer o encaminhamento adequado para a criação dos objetos. É interessante observar que a implementação desse padrão de projeto lidou com esses 3 problemas do sistema anterior.
- ANTES:
if(type.equals("assalariado")) { System.out.println("Informe o salário:"); salary = in.nextDouble(); Salaried salaried = new Salaried(name, adress, id, paymentMethod, salary, sindicate); listEmployees.add(salaried); } else if (type.equals("horista")) { System.out.println("Informe o salário horário:"); salary = in.nextDouble(); Hourly hourly = new Hourly(name, adress, id, paymentMethod, salary, sindicate); listEmployees.add(hourly); } else { System.out.println("Informe a porcentagem de comissão:"); double percent = in.nextDouble(); System.out.println("Informe o salário:"); salary = in.nextDouble(); Comissioned comissioned = new Comissioned(name, adress, id, paymentMethod, salary, percent, sindicate); listEmployees.add(comissioned); } //log method: uso complexo de condicionais //exposição indevida: declaração das subclasses ao invés da principal (ex: Hourly hourly = new Hourly(name, adress, id, paymentMethod, salary, sindicate);) //long parameter list: as variáveis salaried, hourly e comissioned não precisavam ser criadas, visto que o construtor poderia ser passado diretamente em listEmployees.add();
- A fim de resolver os problemas mencionados, foi aplicada uma estratégia primeiramente criando um
map
:employeeMap.put("tipo de empregado", posição);
. Depois, foi criada umaenum
chamadaStrategyEmployee
com os métodos referentes a criação de cada tipo de employee e acessada de acordo com a posição no map. Para dar suporte a essa estratégia, também foi criada uma classe abstrataChoiceEmployee
e os métodos deStrategyEmployees
eram desse tipo. - StrategyEmployee
- ChoiceEmployee
- DEPOIS:
HashMap<String, Integer> employeeMap = new HashMap(); employeeMap.put("horista", 0); employeeMap.put("assalariado", 1); employeeMap.put("comissionado", 2); listEmployees.add(StrategyEmployees.values()[employeeMap.get(type)].getChoiceEmployee(name,adress,id,sindicate,paymentMethod).choiceEmployee()); //As condicionais anteriores foram substituídas por essas linhas de código na função add
- Quando um novo empregado é adicionado, ele pode ser de 3 tipos, horista, assalariado ou comissionado. Para isso foi criado um método
-
Chain Constructors
- Em
Employee
, no sistema anterior, era possível encontar duplicated code em funções construtoras semelhantes e para solucionar isso foi implementado o padrão de projeto: Chain Constructors. Isso, selecionando o construtor com maior número de parâmetros na hora de invocá-los. - ANTES:
public Employee(){ } public Employee(String name, String adress, int id, String paymentMethod, int sindicate) { this.name = name; this.adress = adress; this.id = id; this.paymentMethod = paymentMethod; this.sindicate = sindicate; } public Employee(String name, String adress, int id) { this.name = name; this.adress = adress; this.id = id; }
public Employee(){} public Employee(String name, String adress, int id, String paymentMethod, int sindicate) { this.name = name; this.adress = adress; this.id = id; this.paymentMethod = paymentMethod; this.sindicate = sindicate; } public Employee(String name, String adress, int id) { this(name, adress, id, null, -1); } //como *public Employee(){}* já retorna null por padrão, achei válido não aplicar o padrão
- Em
-
Long Parameter List (code smell)
- Algumas variáveis que não precisavam ser criadas foram excluídas.
- Em
Employee
isso aconteceu na funçãoidGenerate()
- Antes X Depois
//antes public int idGenerate() { Random random = new Random(); int id = random.nextInt(1000) + random.nextInt(35) + random.nextInt(849); int size = listEmployees.size(); for(int i = 0; i < size; i++) {...} return id; //depois public int idGenerate() { Random random = new Random(); int id = random.nextInt(1000) + random.nextInt(35) + random.nextInt(849); for(int i = 0; i < listEmployees.size(); i++) {} return id; } }
- Em
Sindicate
isso também aconteceu e foi modificado pelo mesmo motivo de criar uma variável size ao invés de utilizar o retorno da função.size()
. - Continuando em
Sindicate
, outras duas variáveis foram excluídas. - Antes X Depois
//antes public void addSindicateMember(String name, int employeeId) { int id = idGenerate(); Sindicate member = new Sindicate(name, employeeId, id, 0, 0); listSindicate.add(member); System.out.println(listSindicate.get(listSindicate.size() - 1).showSindicateMember(member)); System.out.println("Adição no sindicato realizada com sucesso!"); } //depois, com a remoção da variável *id* e *member* //duas linhas a menos public void addSindicateMember(String name, int employeeId) { listSindicate.add(new Sindicate(name, employeeId, idGenerate(), 0, 0)); System.out.println(listSindicate.get(listSindicate.size() - 1).showSindicateMember(listSindicate.get(listSindicate.size() - 1))); System.out.println("Adição no sindicato realizada com sucesso!"); }
-
Outros code smells resolvidos
- Para outros code smells presentes no relatório não consegui achar um padrão de projeto em que eles se encaixassem, mas foram mudanças bem simples.
- Algumas funções inutilizadas de
get()
eset()
foram deletadas. - Além disso, a classe
Text
se encaixava em Speculative Generality e foi melhorada para cumprir seu papel de maneira eficiente e não apenas especular sobre ele. Por isso, foram adicionados novos métodos como:changeEmployee()
,undoRedo()
enewCicleOrExit()
. - Os packages também estavam mal organizados e alguns só possuiam apenas uma classe. Para resolver isso, as classes "filhas únicas" foram agrupadas em um package chamado
utils
.