Digamos que eu tenha uma variedade de corredores com os quais preciso encontrar o corredor mais alto, o mais rápido e o mais leve. Parece que a solução mais legível seria:
runners = getRunners();
tallestRunner = getTallestRunner(runners);
fastestRunner = getFastestRunner(runners);
lightestRunner = getLightestRunner(runners);
..onde cada função interage com os corredores e monitora a maior altura, maior velocidade e menor peso. Iterar a matriz três vezes, no entanto, não parece uma boa ideia. Em vez disso, seria melhor fazer:
int greatestHeght, greatestSpeed, leastWeight;
Runner tallestRunner, fastestRunner, lightestRunner;
for(runner in runners){
if(runner.height > greatestHeight) { greatestHeight = runner.height; tallestRunner = runner; }
if(runner.speed > ...
}
Embora isso não seja muito ilegível, pode ficar confuso quando houver mais lógica para cada parte da informação extraída na iteração.
Qual é o meio termo aqui? Como posso usar apenas uma única iteração, mantendo o código dividido em unidades lógicas?
design
code-quality
language-agnostic
readability
mowwwalker
fonte
fonte
Respostas:
O Taskinoor tem a idéia certa, mas há uma maneira melhor de implementá-lo ... desde que seu idioma suporte a passagem de uma referência de função.
Por exemplo, aqui está como eu faria isso no estilo c #:
Isso é trivial para expandir - em vez de definir três funções, você pode definir uma matriz de
Func<Runner, Runner, Runner>
funções anônimas e apenas executá-las. Você pode até fazê-lo com funções regulares comoRunner pickTallest(Runner x, Runner y)
, embora precise defini-las explicitamente. A chave, no entanto, é que você não precisa rastrear o valor de cada estatística - você só precisa saber como comparar duas e escolher a que tiver o melhor valor.Runners
fonte
Essa é uma daquelas coisas em que muitas vezes você deseja operar com uma porção de dados, em vez do princípio OO de "uma única peça de dados".
Então, eu agruparia a lista inteira em uma classe que, na criação, analisa a lista e calcula o que você deseja. Você também usaria essa classe para inserir e remover da lista, para que as informações agrupadas estejam sempre atualizadas.
É isso aí. agora você tem um bloco de lógica independente que responde às suas perguntas com apenas uma iteração na criação e quando você remove objetos.
fonte
Você pode retornar todos os três valores de uma só vez. No pseudo-código próximo ao Scala:
Isso fornecerá uma tupla dos corredores que você está procurando. Você pode fazer o mesmo em outros idiomas. Pode ser necessário pegar uma biblioteca como Guava ou Underscore para fazê-lo e envolver a tupla em um objeto.
fonte
Crie uma classe RunnerStats que calcule as estatísticas em uma única
for loop
, assim como você faz no seu segundo trecho de código.Então você lê as estatísticas nas variáveis via
getters
. Os getters retornam apenas os valores já calculados, eles não calculam nada.Dessa forma, você obtém o melhor das duas soluções: eficiência e legibilidade.
fonte
O problema que você está descrevendo é muito comum: você tem um loop que produz determinados dados e deseja agregar várias "estatísticas" dos dados gerais. A implementação direta é, como você disse, ter várias variáveis locais que são atualizadas a cada iteração:
Isso não tem uma boa separação de preocupações, porque você tem a lógica de agregação alinhada com a produção dos dados. Extrair a lógica de agregação em um método (como proposto nesta resposta ) é uma melhoria, mas o isolamento ainda não é bom: os resultados intermediários e (se necessário) variáveis auxiliares como
greatestHeight
ainda precisam ser variáveis locais.Portanto, a IMHO é a única boa solução para extrair a lógica de agregação e as atribuições em um método.
Como isso pode ser feito? Refatorando primeiro as variáveis locais em campos. Em seguida, você pode, por exemplo, extrair um método
updateStats(runner)
que atualize os campostallestRunner
/fastestRunner
/ ... e os camposgreatestHeight
/greatestSpeed
/ ... correspondentes .Mas isso não piora o isolamento? Sim, a princípio, mas isso pode ser corrigido por uma refatoração de classe de extração : Mova os campos estatísticos e o
updateStats
método para uma nova classe (por exemplo, aninhada). Portanto, no final, você terá a seguinte solução legível e de passagem única:fonte