Estou iniciando um projeto de grupo escolar em Java, usando o Swing. É uma GUI simples no aplicativo de desktop do banco de dados.
O professor nos deu o código do projeto do ano passado para que pudéssemos ver como ele faz as coisas. Minha impressão inicial é que o código é muito mais complicado do que deveria ser, mas imagino que os programadores pensem isso frequentemente quando analisam o código que não escreveram apenas.
Espero encontrar razões pelas quais o sistema dele é bom ou ruim. (Perguntei ao professor e ele disse que veria mais tarde por que é melhor, o que não me satisfaz.)
Basicamente, para evitar qualquer acoplamento entre seus objetos persistentes, modelos (lógica de negócios) e visualizações, tudo é feito com seqüências de caracteres. Os objetos persistentes que são armazenados no banco de dados são hashtables de strings, e os modelos e visualizações "assinam" um ao outro, fornecendo chaves de string para os "eventos" nos quais eles assinam.
Quando um evento é acionado, a visualização ou modelo envia uma sequência para todos os assinantes que decidem o que fazer para esse evento. Por exemplo, em um dos métodos de ouvinte de ação de visualizações (acredito que isso apenas define o bicycleMakeField no objeto persistente):
else if(evt.getSource() == bicycleMakeField)
{
myRegistry.updateSubscribers("BicycleMake", bicycleMakeField.getText());
}
Essa chamada finalmente chega a esse método no modelo Veículo:
public void stateChangeRequest(String key, Object value) {
... bunch of else ifs ...
else
if (key.equals("BicycleMake") == true)
{
... do stuff ...
O professor diz que essa maneira de fazer as coisas é mais extensível e sustentável do que ter a visão simplesmente chamar um método em um objeto de lógica de negócios. Ele diz que não há acoplamento entre as visões e os modelos porque eles não sabem da existência um do outro.
Eu acho que esse é um tipo pior de acoplamento, porque a visão e o modelo precisam usar as mesmas strings para funcionar. Se você remover uma exibição ou modelo ou digitar um erro de seqüência de caracteres, não haverá erros de compilação. Também torna o código muito mais longo do que eu acho que precisa ser.
Quero discutir isso com ele, mas ele usa sua experiência no setor para combater qualquer argumento que eu, o estudante inexperiente, possa apresentar. Há alguma vantagem em sua abordagem que estou perdendo?
Para esclarecer, quero comparar a abordagem acima, com a visão obviamente acoplada ao modelo. Por exemplo, você pode passar o objeto de modelo do veículo para a visualização e, em seguida, para alterar a "marca" do veículo, faça o seguinte:
vehicle.make = bicycleMakeField.getText();
Isso reduziria 15 linhas de código atualmente usadas SOMENTE para definir a marca do veículo em um só lugar, para uma única linha de código legível. (E como esse tipo de operação é realizado centenas de vezes em todo o aplicativo, acho que seria uma grande vitória em termos de legibilidade e segurança.)
Atualizar
Meu líder de equipe e eu reestruturamos a estrutura da maneira que queríamos usando digitação estática, informamos o professor e acabamos dando uma demonstração a ele. Ele é generoso o suficiente para nos deixar usar nossa estrutura, desde que não peça ajuda a ele e se pudermos manter o resto de nossa equipe em dia - o que parece justo para nós.
Respostas:
A abordagem que seu professor propõe é melhor descrita como tipicamente rigorosa e está errada em quase todos os níveis.
O acoplamento é melhor reduzido pela inversão de dependência , que o faz por um despacho polimórfico, em vez de conectar vários casos.
fonte
Seu professor está fazendo errado . Ele está tentando desacoplar completamente a visualização e o modelo, forçando a comunicação a viajar via string nas duas direções (a visualização não depende do modelo e o modelo não depende da visualização) , o que derrota totalmente o objetivo do design orientado a objetos e do MVC. Parece que, em vez de escrever aulas e projetar uma arquitetura baseada em OO, ele está escrevendo módulos diferentes que simplesmente respondem a mensagens baseadas em texto.
Para ser um pouco justo com o professor, ele está tentando criar em Java o que se parece muito com a interface .NET altamente comum chamada
INotifyPropertyChanged
, que notifica os assinantes de eventos de mudança por meio da passagem de strings que especificam qual propriedade foi alterada. Pelo menos no .NET, essa interface é usada principalmente para se comunicar a partir de um modelo de dados para exibir objetos e elementos da GUI (ligação).Se bem feito , adotar essa abordagem pode trazer alguns benefícios¹:
events
mas em Java você teria que criar classes ou objetos e escrever código de inscrição / cancelamento para cada evento.Portanto, em resumo (e para responder à sua pergunta), isso pode ser feito, mas a abordagem adotada pelo professor é falha por não permitir pelo menos uma dependência unidirecional entre a View e o Model. Não é apenas prático, excessivamente acadêmico e não é um bom exemplo de como usar as ferramentas disponíveis.
¹ Pesquise no Google para
INotifyPropertyChanged
encontrar um milhão de maneiras pelas quais as pessoas tentam evitar o uso de cordas mágicas ao implementá-las.fonte
enum
s (oupublic static final String
s) devem ser usados em vez de cordas mágicas.Seu professor não entende OO . Por exemplo, ter uma classe de veículo concreta?
E para que essa classe entenda a marca de uma bicicleta?
O veículo deve ser abstrato e deve haver uma subclasse concreta chamada Bike. Eu seguia as regras dele para obter uma boa nota e depois esquecer o ensino dele.
fonte
Eu acho que você tem um bom argumento, as cordas mágicas são ruins. Alguém na minha equipe teve que depurar um problema causado por seqüências de caracteres mágicas algumas semanas atrás (mas foi no código delas que eles escreveram, então fiquei de boca calada). E aconteceu ... na indústria !!
A vantagem dessa abordagem é que pode ser mais rápido codificar, especialmente para pequenos projetos de demonstração. As desvantagens são que é propenso a erros de digitação e quanto mais a string é usada, maior a chance de um erro de digitação estragar as coisas. E se você quiser alterar uma string mágica, refatorar strings é mais difícil do que refatorar variáveis, pois as ferramentas de refatoração também podem tocar em strings que contêm a string mágica (como uma substring), mas não são elas mesmas a string mágica e não devem ser tocadas. Além disso, você pode precisar manter um dicionário ou índice de strings mágicas para que novos desenvolvedores não comecem a inventar novas strings mágicas com o mesmo objetivo e não perca tempo pesquisando as strings mágicas existentes.
Nesse contexto, parece que um Enum pode ser melhor do que strings mágicas ou mesmo constantes globais de strings. Além disso, os IDEs geralmente oferecem algum tipo de assistência ao código (preenchimento automático, refatoração, encontrar todas as referências, etc ...) quando você usa seqüências de caracteres constantes ou Enums. Um IDE não oferece muita ajuda se você usar seqüências de caracteres mágicas.
fonte
Usar 'experiência no setor' é um argumento fraco. Seu professor precisa apresentar um argumento melhor que esse :-).
Como outros já declararam, o uso de Strings mágicas certamente é desaprovado, o uso de enums é considerado muito mais seguro. Um enum tem significado e escopo , cordas mágicas não. Além disso, a maneira pela qual seu professor está dissociando as preocupações é considerada uma técnica mais antiga e mais frágil do que a usada atualmente.
Vejo que o @backtodos cobriu isso enquanto respondia, então adicionarei minha opinião de que, usando Inversão de controle (da qual a injeção de dependência é um formulário, você percorrerá toda a estrutura do Spring na indústria antes de muito tempo). ..) é considerada uma maneira mais moderna de lidar com esse tipo de dissociação.
fonte
Sejamos claros; inevitavelmente, há algum acoplamento lá. O fato de existir um tópico assinável é um ponto de acoplamento, assim como a natureza do restante da mensagem (como “cadeia única”). Dado isso, a questão torna-se uma questão de saber se o acoplamento é maior quando realizado por meio de strings ou tipos. A resposta para isso depende se você está preocupado com o acoplamento distribuído ao longo do tempo ou no espaço: se as mensagens serão preservadas em um arquivo antes de serem lidas posteriormente, ou serão enviadas para outro processo (especialmente se que não está escrito no mesmo idioma), o uso de strings pode tornar as coisas muito mais simples. A desvantagem é que não há verificação de tipo; os erros não serão detectados até o tempo de execução (e às vezes nem isso).
Uma estratégia de mitigação / comprometimento para Java pode ser usar uma interface digitada, mas onde essa interface digitada está em um pacote separado. Ele deve consistir apenas em Java
interface
e tipos de valor básico (por exemplo, enumerações, exceções). Não deve haver nenhum implementações de interfaces em que o pacote. Todo mundo implementa isso e, se for necessário transmitir as mensagens de maneira complexa, uma implementação específica de um delegado Java pode usar seqüências de caracteres mágicas, conforme necessário. Também facilita a migração do código para um ambiente mais profissional, como JEE ou OSGi, além de ajudar muito em pequenas coisas, como testes ...fonte
O que seu professor está propondo é o uso de "cordas mágicas". Embora ele "junte frouxamente" classes entre si, permitindo mudanças mais fáceis, é um antipadrão; As seqüências de caracteres devem muito, MUITO raramente, ser usadas para conter ou controlar instruções de código e, quando isso absolutamente acontecer, o valor das seqüências de caracteres que você está usando para controlar a lógica deve ser definido central e constantemente, para que haja UMA autoridade no valor esperado de qualquer string em particular.
A razão pela qual é muito simples; as seqüências de caracteres não são verificadas pelo compilador quanto à sintaxe ou consistência com outros valores (na melhor das hipóteses, elas são verificadas quanto à forma adequada em relação aos caracteres de escape e a outra formatação específica do idioma na sequência). Você pode colocar o que quiser em uma string. Como tal, você pode obter um algoritmo / programa irremediavelmente quebrado para compilar, e não é até que seja executado que ocorre um erro. Considere o seguinte código (C #):
... todo esse código é compilado, primeira tentativa, mas o erro é óbvio com uma segunda olhada. Existem inúmeros exemplos desse tipo de programação e todos estão sujeitos a esse tipo de erro, mesmo que você defina cadeias como constantes (porque as constantes no .NET são gravadas no manifesto de cada biblioteca na qual são usadas, o que deve todos serão recompilados quando o valor definido for alterado para que o valor seja alterado "globalmente"). Como o erro não é detectado no tempo de compilação, ele deve ser detectado durante o teste em tempo de execução, e isso é garantido apenas com 100% de cobertura de código em testes de unidade com exercício adequado de código, o que geralmente é encontrado apenas no mais seguro contra falhas absoluto , sistemas em tempo real.
fonte
Na verdade, essas classes ainda estão fortemente acopladas. Só que agora eles estão fortemente acoplados de tal maneira que o compilador não pode dizer quando as coisas estão quebradas!
Se alguém alterar "BicycleMake" para "BicyclesMake", ninguém descobrirá que as coisas estão quebradas até o tempo de execução.
Erros de tempo de execução são muito mais caros de corrigir do que erros de tempo de compilação - isso é apenas todo tipo de mal.
fonte