Os padrões devem ser usados apenas onde possam ser a melhor solução ou ajudar na criação de uma boa solução (você concorda?).
Vejo padrões de design estritamente como detalhes de implementação. Se você documentar suas APIs públicas e programar para essa documentação, em geral não importará (ou afetará muito você) onde você possui padrões de design. Ou seja, você não diz "Eu tenho um padrão de ponte aqui e implementarei um visitante em cima dele". Em vez disso, é "esta classe terá implementações diferentes em vários sistemas operacionais, portanto será implementada usando um padrão de ponte". Então, quando você o usa, fica indiferente ao fato de ele ser implementado como uma ponte - porque você olha para a API pública, não um padrão de ponte.
quanto esforço se deve realmente investir na criação de projetos flexíveis e pouco acoplados?
O acoplamento frouxo pode ser alcançado seguindo um conjunto simples de regras. Se você respeitar isso, seu código será (mais) fracamente acoplado, conforme você o escrever (ou seja, qualquer esforço já faz parte do processo de desenvolvimento).
Entre as regras (não uma lista exaustiva):
- defina suas interfaces pensando (ou escrevendo) no código do cliente (como a classe será usada), não no que a classe fará (por exemplo, desejando interface, não implementação)
- "diga, não pergunte"
- construir objetos a partir de peças já criadas
- transmita ao construtor os objetos reais que você usará (não fábricas para os membros, parâmetros para as fábricas dos parâmetros ou qualquer coisa assim).
- SECO (se você tiver duas linhas que aparecem na mesma ordem em dois lugares, extraia-as em uma função separada e assim por diante).
- Se a criação de um objeto for uma operação mais complexa, implemente a criação das peças intermediárias como um método / classe de fábrica (ou seja, não no corpo do construtor).
- YAGNI (crie as coisas conforme necessário, não antes).
Essas regras são seguidas de maneira diferente, dependendo do idioma, metodologia de desenvolvimento seguida por sua equipe (por exemplo, TDD), restrições de orçamento de tempo e assim por diante.
Por exemplo, em Java, é uma boa prática definir sua interface como um interfacecódigo de cliente e escrever nele (instancie a interface com uma classe de implementação).
Em C ++, por outro lado, você não possui interfaces, portanto, você pode escrever a interface apenas como uma classe base abstrata; Como no C ++ você só usa herança quando possui um requisito forte (e, como tal, evita a sobrecarga de funções virtuais desnecessárias), provavelmente não definirá a interface separadamente, apenas o cabeçalho da classe).
Aqueles que se opõem aos padrões de design dizem que os custos para usá-los geralmente superam os benefícios.
Eu acho que eles estão fazendo errado. Se você escrever um código fracamente acoplado (e DRY), a integração de padrões de design com um esforço extra mínimo. Caso contrário, você precisará adaptar seu código para implementar um padrão de design.
Se você precisar fazer muitas alterações para implementar um padrão de design, seu problema não é o padrão de design - sua base de código é monolítica e fortemente acoplada. Esse é um problema de design ruim / subótimo, não um problema de padrões de design.
O que eu gostaria de saber é quanto esforço devo realmente criar na criação de níveis adicionais de abstração e design, apenas para permitir que meu aplicativo siga os princípios de OO, como acoplamentos soltos, design de programa em uma interface etc. isto? Quanto esforço devo colocar nisso?
Suas perguntas assumem (não declaradas) que o único benefício do acoplamento flexível é a capacidade de implementar facilmente padrões de design. Não é.
Entre os benefícios do acoplamento solto estão:
- refatoração e reformulação da flexibilidade
- esforço menos desperdiçado
- testabilidade
- possibilidade aumentada de reutilizar o código
- simplicidade de design
- menos tempo gasto no depurador
... e alguns outros que não me vêm à cabeça agora.