Como a pista na primeira parte indica, estou usando o livro do Joshua Bloch como referencia principal nesta solução e para escrever este post. Então vamos ver como a solução para o problema da carga de dados ficou mais elegante.
Relembrando o problema, precisamos ler os dados de um arquivo CSV e fazer a carga para um repositório. No post anterior, tivemos problemas para relacionar o índice do array, o nome do cluster no repositório e o impacto. Mais detalhes aqui.
Mas o que é um Enum? Nas palavras de Bloch:
An enumerated type is a type whose legal values consist of a fixed set of constants, such as the season of the year, the planets in the solar system...Um exemplo básico de um Enum é demonstrado abaixo:
public enum Apple {FUJI, PIPPIN, GRANNY_SMITH}
Bom, vamos incrementar um pouco essa estrutura para que comece a nos ajudar na solução.
package enums;
public enum Cluster {
RIO_DE_JANEIRO(2), SAO_PAULO(3), FORTALEZA(4), PORTO_ALEGRE(5), MANAUS(6);
private Integer index;
Cluster(Integer index){
this.index = index;
}
public Integer getIndex() {
return index;
}
}
Neste exemplo, já replicamos o relacionamento INDICE - CONSTANTE presente na solução anterior, com uma pequena(?) diferença: as constantes estão em um artefato que vai cuidar delas com carinho.
Vamos ao segundo problema. A relação nome do Cluster - INDICE. Para resolver este problema, vamos sobrescrever o método toString(). Joshua Bloch diz para considerarmos a implementação de um método fromString() quando sobrescrevermos o método toString(). Nesta consideração, devemos lembrar que todo código não utilizado é muda.
O enum abaixo contém o código que implementa fromString() para qualquer enum que tenha apenas uma representação em String para cada constante. Este código foi retirado do Effective Java.
package enums;
import java.util.HashMap;
import java.util.Map;
public enum Cluster {
RIO_DE_JANEIRO(2) {
@Override
public String toString() {
return "Rio de Janeiro";
}
}, SAO_PAULO(3) {
@Override
public String toString() {
return "São Paulo";
}
}, FORTALEZA(4) {
@Override
public String toString() {
return "Fortaleza";
}
}, PORTO_ALEGRE(5) {
@Override
public String toString() {
return "Porto Alegre";
}
}, MANAUS(6) {
@Override
public String toString() {
return "Manaus";
}
}, CUIABA(7) {
@Override
public String toString() {
return "Cuiabá";
}
};
private Integer index;
@Override
public abstract String toString();
Cluster(Integer index){
this.index = index;
}
private static final Map
static {
for (Cluster cluster: values()) {
stringToEnum.put(cluster.toString(), cluster);
}
}
public static Cluster fromString(String nomeCluster) {
return stringToEnum.get(nomeCluster);
}
public Integer getIndex() {
return index;
}
}
Pronto. Relacionamos cada constante ao seu respectivo nome no repositório.
Restou um ultimo problema para resolver: recuperar os dados do arquivo e informar o impacto. O leitor trabalha com o Enum da seguinte forma:
Cluster[] clusters = Cluster.values();
for (Cluster cluster : clusters) {
mapaDeClusters.put(cluster, partes[cluster.getIndice()].equals("1"));
}
Bem, lembrando o primeiro post, 1 indica impacto, 0 não e "partes" é o array resultado do split de uma linha do csv.
Com constantes, para alimentarmos este Map, precisaríamos incluir um por um. Outro ponto importante é que não parametrizamos mais o Map com um Integer que tornava obscuro o seu sentido. Agora temos uma estrutura que representa alguma coisa no nosso sistema. Isso fica mais claro agora, quando vamos recuperar os dados do Map.
Set
for (Cluster nomeCluster : setKey) {
if (mapaDeClustersImpactados.get(nomeClusters)) {
ClusterImpactado impactado = clusterService.getByDescricao(nomeClusters.toString());
if (!impactado.isEmpty()) {
demanda.addClusterImpactado(impactado);
}
}
}
Lembrando que ImpactadorCluster é a estrutura que o leitor devolve.
Desta forma, temos uma solução mais elegante, pois a manutenção é de extrema facilidade. O ato de colocar ou tirar dados do mapa de clusters está completamente desacoplado da complexidade dos indices, nomes e tudo que pode envolver a leitura e transformação do CSV. Se a ordem dos índices mudar ou for necessário acrescentar outro cluster, só precisamos mudar o enum. Se algum nome mudar, também só precisamos mudar o enum.
O ponto frágil deste código é o altíssimo acoplamento de toString() com os dados do repositório. Este acoplamento no momento é importante para lidar com a natureza no arquivo de entrada, que não possui um padrão definido. Com o enum, obrigamos a sobrescrita do método toString(), já que se não o fizermos receberemos um erro de compilação.
O poder dos "enumerated types" é maior que essa demonstração prática, sendo um recurso interessante para o uso de estratégias para substituir switches e if's.
Os dados do exemplo que poderiam representar quebra de sigilo são fictícios ou foram omitidas as suas implementações.
Referência: Effective Java 2nd Edition - Joshua Bloch
Nenhum comentário:
Postar um comentário