Nosso domínio do conhecimento envolve pessoas caminhando sobre uma placa de registro de pressão com os pés descalços. Fazemos reconhecimento de imagem que resulta em objetos da classe 'Foot', se um pé humano for reconhecido nos dados do sensor.
Existem vários cálculos que devem ser realizados nos dados do pé.
Agora, qual API seria melhor:
class Foot : public RecognizedObject {
MaxPressureFrame getMaxPressureFrame();
FootAxis getFootAxis();
AnatomicalZones getAnatomicalZones();
// + similar getters for other calculations
// ...
}
Ou:
class Foot : public RecognizedObject {
virtual CalculationBase getCalculation(QString aName);
// ...
}
Agora, há muitos prós e contras com os quais eu posso pensar, mas não consigo decidir quais são os mais importantes. Observe que este é um aplicativo de usuário final, não uma biblioteca de software que vendemos.
Algum conselho?
Alguns profissionais da primeira abordagem podem ser:
- BEIJO - tudo é muito concreto. A API, mas a implementação também.
- valores de retorno fortemente digitados.
- herdar dessa classe é à prova de idiotas. Nada pode ser substituído, apenas adicionado.
- A API está muito fechada, nada entra, nada pode ser substituído, portanto, menos pode dar errado.
Alguns contras:
- O número de getters aumentará, à medida que cada novo cálculo que inventamos for adicionado à lista
- É mais provável que a API mude e, se forem introduzidas alterações mais recentes, precisamos de uma nova versão da API, o Foot2.
- no caso de reutilização da classe em outros projetos, talvez não precisemos de todos os cálculos
Alguns profissionais da segunda abordagem:
- mais flexível
- é menos provável que a API mude (assumindo que a abstração esteja correta, caso contrário, a alteração custará mais)
Alguns contras:
- digitado livremente. Precisa de transmissões em todas as chamadas.
- o parâmetro string - tenho sentimentos ruins sobre isso (ramificação nos valores da string ...)
- Não há nenhum caso / requisito de uso atual que exija flexibilidade extra, mas pode haver no futuro.
- a API impõe restrições: todo cálculo precisa derivar de uma classe base. A obtenção de um cálculo será forçada através deste método 1, e a passagem de parâmetros extras será impossível, a menos que planejemos uma maneira ainda mais dinâmica e super flexível de passar parâmetros, o que aumenta ainda mais a complexidade.
enum
e ativar seus valores. Ainda assim, acho que a segunda opção é má, porque se desvia do KISS.getCalculation()
.Respostas:
Eu acho que na primeira abordagem vai valer a pena. As strings mágicas podem criar os seguintes problemas: Erros de digitação, uso indevido, segurança do tipo de retorno não trivial, falta de conclusão de código, código pouco claro (essa versão possui esse recurso? Acho que descobriremos em tempo de execução). O uso de enums resolverá alguns desses problemas, mas vamos analisar os contras que você levantou:
É verdade que isso pode ser irritante, mas mantém as coisas agradáveis e rigorosas e fornece a conclusão do código em qualquer lugar do projeto em qualquer IDE moderno, com bons comentários de cabeçalho que são muito mais úteis que enumerações.
É verdade, mas esse é realmente um grande profissional;) você pode definir interfaces para APIs parciais e não precisa recompilar a classe dependente que não é afetada pelas APIs mais recentes (portanto, não há necessidade do Foot2). Isso permite uma melhor dissociação, a dependência agora é da interface e não da implementação. Além disso, se uma interface existente for alterada, você terá um erro de compilação nas classes dependentes, o que é ótimo para evitar código obsoleto.
Não vejo como o uso de seqüências de caracteres mágicas ou enumerações ajudará nisso ... Se eu entendi corretamente, você inclui o código na classe Foot ou o divide em algumas classes menores, e isso vale para as duas opções
fonte
IEnumerable<T>.Count
], essa abordagem pode permitir que o código aproveite os benefícios de desempenho de novas recursos de interface ao usar implementações que os suportam, mas permaneçam compatíveis com implementações antigas.Eu recomendaria a opção 3: Deixe claro que os cálculos não são uma parte intrínseca da abstração de a
Foot
, mas operam nela. Em seguida, você pode dividirFoot
e os cálculos em classes separadas, assim:Dessa forma, você ainda terá uma digitação forte do seu cálculo e poderá adicionar novos sem afetar o código existente (a menos que tenha cometido um erro grave na quantidade de informações expostas por
Foot
).fonte