É prática aceitável dar a um objeto um ponteiro para “o mundo”?

5

Muitas vezes me encontro em situações em que objetos precisam se comunicar entre si. Por exemplo, um botão pode precisar falar com várias caixas de texto. Seria apropriado simplesmente construir cada widget com um ponteiro para o contêiner para todos eles? Seria melhor dar um ponteiro para um mapa de contêiner de recursos onde o objeto pode localizar outro objeto por cadeia de caracteres ou algo assim? Esta área sempre foi muito vaga para mim. Eu poderia facilmente implementar tudo o que eu quero fazer se eu apenas construísse objetos com ponteiros para containers de todos os outros objetos, mas isso parece errado. No caso de um widget, seria realmente mais adequado se o widget não soubesse nada sobre o mundo exterior e, em vez disso, seus ouvintes de ação fossem construídos com acesso a recursos?

Obrigado

Eu entendo que é uma má idéia, mas quais são algumas soluções nessas situações, por exemplo: bons padrões de projeto para software orientado a gui?

Se o clique de um botão precisar gravar um arquivo, como isso pode ser feito de maneira limpa? Ouvintes de ação? Mas onde eles são criados e por quê?

    
por jmasterx 19.05.2011 / 06:21
fonte

3 respostas

4

É melhor separar a lógica de negócios do código gerado pelo estado / interface do usuário. Se você adicionar a lógica biz diretamente aos ouvintes da Action gerados, ela será um antipadrão. Você acabará com uma lógica muito fragmentada que fica mais difícil de manter à medida que você adiciona mais botões.

Crie sua lógica básica de negócios como você faria com qualquer problema de software. Adicione GUI em cima disso como um ativador. Nos piores cenários, você poderia consultar a GUI para descobrir o estado atual das caixas de seleção, etc., mas, idealmente, você deve manter esse estado em sua camada de lógica de Biz. Desacoplar assim vai poupar muita dor depois. Leia sobre os padrões MVC.

Depois de percorrer esse caminho, você descobrirá que não precisa de um ponteiro mundial, mas apenas de um ponteiro para o objeto controlador, que pode lhe dizer o que precisar.

    
por 19.05.2011 / 07:02
fonte
0

Muitas perguntas diferentes aqui, você pode ter sido melhor perguntar isso em 2 ou 3 postagens separadas, mas vamos ver o que acontece ...

1) "o mundo" eu acho que é um termo relativo. Eu não daria um valor de ponteiro para "o mundo", mas com base em seu exemplo, eu diria que vá em frente porque eu não consideraria um contêiner de um widget para ser "o mundo". Por outro lado, se você criasse um conjunto de objetos com base na solicitação do cliente externo e, em vez de identificadores exclusivos, usasse diretamente ponteiros como os identificadores, isso estaria dando um ponteiro para a memória interna para o mundo. Eu evitaria fazer isso.

2) Eu consideraria objetos (ou widgets) contendo ponteiros para outros objetos (ou widgets) para ser automaticamente design ruim. Você obviamente quer manter as coisas o mais soltas possível, mas eu posso ver algumas situações, onde isso seria aceitável. Ligadamente acoplado significa simplesmente que você quer que cada um de seus objetos (ou widgets) só saiba tanto sobre os outros como absolutamente necessário (e não faça quaisquer suposições sobre implementações internas)

3) Eu fiz inúmeros desenhos onde você tem um contêiner pai e um conjunto de filhos. Uma coisa que eu sempre tento fazer é evitar dependências circulares onde o objeto A sabe sobre B e B sabe sobre A. Normalmente, quando você faz isso, você está pedindo por problemas. Em vez disso, eu definiria um filho (nossa classe de widget) e, ao lado dele, definiria a interface "IWidgetOwner" ou "IWidgetKeeper" (referência de ghostbusters). Em seguida, faça o pai implementar essa interface e passe um ponteiro para cada filho. Agora você tem um relacionamento hierárquico muito claro. Seu contêiner sabe sobre os widgets que ele contém, mas os widgets não sabem nada sobre seu contêiner específico. Em vez disso, eles podem ser colocados em praticamente qualquer contêiner que implemente sua interface de "goleiro".

4) Dito tudo isso, se você estiver fazendo um trabalho específico da interface do usuário, eu ficaria longe de adicionar muita lógica de negócios dentro dos próprios controles (widgets) da GUI. Em vez disso, eu teria uma camada (classe) separada que criaria assinaturas nos manipuladores de eventos e definiria qual ação deveria ser executada quando determinados eventos fossem disparados. Dessa forma, seu código de widget permanece genérico e reutilizável, e toda a lógica de negócios é agrupada em um único lugar. Assim, quando você precisa alterá-la, não precisa procurar em todo o código.

5) Um botão nunca "precisa" de escrever um arquivo. Em vez disso, seu aplicativo precisa gravar um arquivo em resposta a um clique do usuário. Eu sempre separava o código que "funciona" da interface do usuário tanto quanto eu posso. Pense no cenário em que você deseja que um segundo botão ou tecla de acesso global grave o mesmo arquivo? Ou se você quiser adicionar automação e você precisa escrever o mesmo arquivo, mas sem nenhuma interface gráfica. Quando você inicia um projeto com uma interface do usuário, comece definindo uma linha muito clara entre sua GUI e seu trabalho. Pode parecer muito sobrecarga, mas é apenas um exercício mental e depois de fazê-las algumas vezes, vai ficar muito mais natural para que a sobrecarga quase desapareça. Mas você estará escrevendo código que é mais fracamente acoplado e melhor posicionado para expansão futura.

    
por 19.05.2011 / 07:11
fonte
0

Depende do escopo do seu aplicativo. Se você está falando sobre um utilitário rápido e sujo com um público limitado, com certeza, isso seria ótimo. Com um público maior, você pode encontrar recursos e melhorias que serão acumulados rapidamente.

Colocar um gerente intermediário entre as ações do usuário e as exibições de dados pode ser um esforço útil para manter seu código extensível em tais circunstâncias. Uma maneira estabelecida de fazer isso é seguir um padrão de Model / View / Controller. Ou, se você estiver usando o WPF, examine um padrão do MVVM usando um ViewModel, uma ligação de dados e comandos. Indo com isso cedo é um trabalho extra, mas irá colocá-lo à frente da curva, evitando grandes refatoradores mais tarde.

Finalmente, apenas para observar, quando o código tem referências a controles, ter um intermediário só oferece proteção profunda da hacker. No Win32, WinForms e WPF (e praticamente todas as estruturas de interface do usuário) você pode percorrer a árvore de controle. Assim, seus controles e seu código associado sempre terão a capacidade de acessar todos os outros, mesmo com uma arquitetura MVC ou MVVM.

    
por 19.05.2011 / 09:03
fonte