Eu tenho uma classe, que envolve outra classe de um tipo de base comum. Como a interface do tipo base é bastante grande, isso envolve escrever muitas funções de passagem. Estou procurando uma maneira de evitar isso.
Vamos fazer um exemplo:
Car
/ \
Volvo VolvoWithTrailer
Agora eu tenho que implementar todas as funções na interface do carro para o VolvoWithTrailer e chamar a função apropriada no objeto Volvo envolvido, exceto talvez GetMaxSpeed (), que retornará algo mais baixo. Basicamente, terei muitas funções como
int VolvoWithTrailer::GetNumSeats() {
return mVolvo.GetNumSeats()
}
Uma maneira óbvia de resolver isso seria fazer da VolvoWithTrailer uma subclasse da Volvo
Car
|
Volvo
|
VolvoWithTrailer
mas isso parece violar o princípio de favorecer a composição sobre a herança.
De que outra forma eu poderia evitar escrever todos esses wrappers (a linguagem é C ++)? Ou - se essa é a sua posição - por que devo escrevê-las / usar apenas herança? Existe alguma mágica de modelo que possa ajudar com isso?
fonte
Respostas:
Minha opinião é que você deve escrever o que precisar para fazer o estabilidade e a manutenção do programa longo prazo . Qual é o sentido de evitar escrever 20 linhas de código hoje, se toda vez que você toca em algo que usa esse código ou volta para manter essa Classe, isso custa mais 5 minutos ou mais porque você não investiu hoje?
Então a pergunta se torna "o que você precisa escrever?" Eu não acho que você fornecer informação suficiente para ser capaz de dar uma resposta definitiva, por isso vou listar algumas coisas que eu poderia pensar em fazer uma decisão:
1. Você precisa ter o objeto Trailer sozinho, agora ou em um futuro previsível?
Nesse caso, você tem um argumento bastante bom para criar o wrapper em torno de ambos os objetos compostos, pois você já precisará envolver um ou outro. Pode muito bem ser consistente.
2. Existe um dos três tipos (Car, Trailer, CarWithTrailer) em uma área do código em que os desenvolvedores acessam com frequência ou que parecem se tornar assim?
Nesse caso, tenha muito cuidado, pois as ramificações da escolha da coisa errada podem ser muito amortizadas sempre que o código for tocado. Caso contrário, pode não fazer qualquer diferença o que você decidir. Basta escolher uma direção e seguir em frente.
3. O que é mais fácil de entender?
Será que uma abordagem se repete quando alguém que está atrás de você "recebe" imediatamente o que você está tentando fazer? Seus colegas de equipe têm tendências específicas que podem dificultar uma abordagem para sua manutenção? Se tudo for igual, escolha a solução que impõe a menor carga cognitiva.
4. Há vantagens adicionais em usar uma abordagem em detrimento de outra?
Uma coisa que me impressiona é que a idéia do invólucro tem uma vantagem distinta se você escrever que o CarWithTrailerWrapper pode envolver qualquer carro e qualquer trailer em um CarWithTrailer. Então, você acaba escrevendo todos os seus métodos de passagem, mas apenas os escreve uma vez , em vez de uma vez para cada classe de carro.
Isso torna seu investimento inicial na escrita dos métodos de passagem muito mais baratos à medida que você adiciona mais carros e reboques. Também ajuda a reduzir a tentação de acoplar as coisas diretamente ao Volvo ou VolvoWithTrailer, enquanto reduz as conseqüências do acoplamento ao CarWithTrailerWrapper, pois você pode fazer muito mais com apenas essa implementação.
Talvez haja vantagens distintas que você obteria de graça usando o método de extensão, mas eu não as vejo.
OK, parece que eu me convenci a seguir em frente e a preencher os métodos de passagem, para aplicativos não triviais.
Como não sou programador de C ++, não tenho idéia de quais ferramentas de geração de código estão disponíveis para você. O IDE que eu uso pode gerar métodos a partir de uma Interface, e eu posso adicionar modelos de código que tornariam as passagens de escrita bastante simples. Se você não tiver acesso a um IDE que faça isso, poderá realmente ir muito longe, deixando o Excel escrever código para você .
fonte
E aí está o seu problema.
As interfaces devem lidar apenas com uma responsabilidade. Mantê-los finos e focados limita a quantidade de trabalho de passagem que você pode precisar no caso de um decorador, proxy ou outro invólucro (além de tornar a classe mais simples de usar, testar, manter e estender).
fonte