Por que é considerada uma prática recomendada empacotar o código do programa e o código da interface gráfica em diferentes classes?

15

Então, meu professor me diz que é muito importante não encapsular o código do programa e o código da interface gráfica nas mesmas classes, mas mantê-los completamente independentes. Atualmente, estou escrevendo um jogo para iPhone com uma grade. para mim, faz muito mais sentido criar a grade gráfica e o código técnico na mesma classe "Grade". Outro programador desaprovará isso? É realmente muito importante manter a interface gráfica e o código independentes. Que problemas surgirão se não o fizer?

Obrigado!

EDIT: obrigado pessoal! Seria bom escrever primeiro o projeto e depois copiar o código para formar o design da separação de preocupações. Eu sei que isso pode derrotar totalmente o objetivo, mas apenas como prática ... Para que da próxima vez eu possa aplicar esse padrão de design desde o início?

John
fonte

Respostas:

17

O conceito ao qual seu professor está se referindo é algo chamado Separação de Preocupações.

Para ilustrá-lo no seu contexto, se você concluir o programa e decidir que deseja portá-lo para o Android; você precisará reescrever muito mais código do que se tivesse mantido a lógica da grade separada.

Um controle de interface deve se preocupar apenas em desenhar o que foi dito, a lógica da grade deve se preocupar apenas com o que está na grade, não como desenhá-la.

Isso ajuda?

Russ Clarke
fonte
Graças ajudou. O fato é que é muito mais fácil visualizar meu produto final quando encapsulo os dois em uma classe. Essa é uma razão válida para eu não seguir a "separação de preocupações"? Ou é absolutamente necessário e eu não poderia me chamar de programador adequado: p?
Um efeito positivo desta separação é que você não tem que reescrever sua lógica de jogo, se você escolher para substituir o seu gui por exemplo
@ John - Escreva um documento de especificação se precisar visualizar seu design. Se você pode descrevê-lo, pode começar a separar o código da interface gráfica da própria lógica do jogo.
Ramhound
3
Também facilita o teste do código da grade. Testar as GUIs é doloroso (devido a possíveis problemas de confusão nos ambientes), portanto, obter uma GUI é uma camada fina "obviamente correta" sobre algo testável é uma grande vitória. (Novamente, isso é separação de preocupações.)
Donal Fellows
1
@ John: Alguns de nós aprendem melhor fazendo. Supondo que esse projeto não seja tão grande, tente escrevê-lo como uma única classe e trabalhe no iPhone. Agora mova-o para o Android, acompanhando seus "pontos problemáticos". Finalmente, reescreva-o como sugerido por Russ C. Acho que você verá por que a separação da lógica e da apresentação é o caminho a seguir.
Peter Rowell
4

Para facilitar a alteração do seu código . E se amanhã você não quiser usar uma grade, mas uma lista? Quando sua GUI é separada da sua lógica, é fácil fazer isso.

Além disso, você escreverá um código mais reutilizável . Se sua GUI não contiver seu código técnico, você também poderá reutilizá-lo. Crie uma grade sofisticada com todas as opções uma vez e poderá usá-la em outros projetos. A mistura da GUI e do código técnico impedirá que você faça isso.

Também fornece código mais fácil de ler. Se sua grade faz apenas a funcionalidade da GUI, é mais fácil entender ou alterar seu código.

Carra
fonte
3

A abordagem geral da programação orientada a objetos para uma separação de preocupações , onde o código é separado em tarefas lógicas. Inicialmente, isso pode parecer mais trabalho. Mas à medida que seu projeto cresce, fica mais fácil rastrear e gerenciar seu código.

Por esse motivo, provavelmente seria melhor separar o código responsável por exibir uma grade e o código que lida com os dados que podem ser exibidos nessa grade.

Jonathan Wood
fonte
1

Quando a Separação de preocupações é aplicada a uma estrutura de aplicativo, o resultado é uma arquitetura de várias camadas (ou arquitetura de N camadas ) http://en.wikipedia.org/wiki/Multitier_architecture .

StuperUser
fonte
0

Para desenvolver as outras respostas e dar um exemplo, você deve, de alguma forma, permitir a injeção de sua lógica / dados em sua grade ou vice-versa.

Seu controle de grade pode expor um Rendermétodo ou um DataBindmétodo.

class GridControl
{
    public Render(GridData data) { ... }
}

ou

class GridControl
{
    public DataBind(GridData data) { ... }
}

Em seguida, sua unidade lógica pode pegar o GridControl e vincular um objeto de dados a ele ou manualmente chamar render com o objeto de dados sempre que algo mudar.

Seu GridLogic também deve ter uma referência ao GridControl para que ele possa se vincular a qualquer entrada / evento que esteja acontecendo.

A idéia por trás da ligação de dados é que seu controle de grade observe os dados em busca de quaisquer alterações e se processe novamente. Ao expor uma função de renderização, sua unidade lógica renderiza manualmente o controle.

De qualquer maneira, dividir sua lógica e grade dessa maneira permite alterar mais facilmente uma da outra sem quebrar nada. Você também pode escrever um novo controle como um ListControlpara mostrar seus dados como uma lista em vez de uma grade sem precisar reescrever toda a sua lógica.

Raynos
fonte
0

Eu recomendo fortemente que você dê uma olhada na arquitetura MVC .

É um refinamento do conceito que você mencionou (separação do código do programa e da interface gráfica). MVC significa Model-View-Controller. Aqui, o Model é o dado, View é o código da interface gráfica e COntroller é o código que processa os dados.

Dessa forma, você criou três partes do seu programa. Cada peça pode ser substituída sem exigir alterações nas outras duas partes.

DPD
fonte
0

Depende dos tipos de mudanças futuras que você pode esperar que ocorra. O que você deseja minimizar é o número de alterações manuais de código necessárias para implementar corretamente cada alteração funcional.

Onde o MVC vence é se as alterações estiverem confinadas à parte V, ou "Visualizar".

Na minha experiência, é muito mais provável que as mudanças afetem todas as três partes; portanto, é melhor que elas não sejam separadas. Para mostrar o que quero dizer, há muito tempo uso uma técnica que desenvolvi chamada Diálogos Dinâmicos , na qual um novo requisito, como "permitir que o usuário edite o nome e quando concluir a execução do XYZ" é inserido no código-fonte como um único bloco de texto:

if(deTextEdit(&sName)){
  // do XYZ
}

em vez de várias edições separadas, para especificar que o campo de edição existe, criar um identificador exclusivo para ele, vinculá-lo à variável de modelo e vinculá-lo ao manipulador de eventos de foco perdido.

Se você acessar esse link, verá um exemplo mais complexo.

Basicamente, a idéia é transformar o código em um idioma específico do domínio, de modo a minimizar o número de edições para realizar o objetivo. O motivo pelo qual você deseja fazer isso não é apenas reduzir o esforço, mas reduzir a oportunidade de introduzir bugs, esquecendo ou codificando incorretamente uma ou mais edições. Também reduz o tamanho do código fonte em aproximadamente uma ordem de magnitude.

Não é grátis. Ele introduz uma curva de aprendizado única para o programador.

Mike Dunlavey
fonte
0

A interface gráfica depende do sistema, enquanto o núcleo do jogo é um algoritmo totalmente independente do sistema em que é executado. Manter os dois apartamentos facilitará a manutenção, teste e depuração do programa, porque as alterações em um subsistema não afetam a maneira como o outro funciona. Mesmo que você não se preocupe com a portabilidade, aposto que se importa com a robustez e a manutenção do seu programa.

Gus
fonte