Artigo Clube Delphi 90 - MVC (Model-View-Controller)

Você precisa estar logado para dar um feedback. Clique aqui para efetuar o login
Para efetuar o download você precisa estar logado. Clique aqui para efetuar o login
Confirmar voto
0
 (6)  (0)

Aplique esse poderoso padrão em suas aplicações cliente/server.

Esse artigo faz parte da revista Clube Delphi Edição 90. Clique aqui para ler todos os artigos desta edição

POO

MVC (Model-View-Controller)

Aplique esse poderoso padrão em suas aplicações cliente/server

 

A grande maioria dos programadores Delphi desenvolve seus sistemas utilizando o modelo Cliente/Servidor, dividindo assim teoricamente seu sistema em duas camadas: interface e banco de dados.

É muito comum vermos no código de um formulário a construção de sentenças SQL e validação de regras de negócio, tudo muito RAD, já que é neste ponto que o Delphi se destaca. É possível construir rapidamente um cadastro e sua manutenção utilizando Delphi, porém um sistema completo não é composto apenas por cadastros. Muita lógica está envolvida.

Além disso existe outro fator que muitos não atentam: a vida do sistema. Por quanto tempo ele vai rodar. Se você quer desenvolver um sistema que tenha uma vida longa tem que pensar no tempo e custo das manutenções que ocorrerão.

Nessa hora que surgirão os problemas em se utilizar o RAD sem pensar na arquitetura do sistema.  É muito fácil construir uma aplicação arrastando componentes, gerar os eventos no formulário e dentro deles mesmo acessar banco de dados, SQL e etc. O difícil será reutilizar rotinas, regras de negócio e aplicação de testes, que juntos garantem uma facilidade na adequação dos sistemas para as necessidades dos usuários.

Agora você pode estar se perguntando, por onde começo?  A primeira coisa a se fazer é pensar que seu software é composto por camadas e não apenas por formulários, relatórios e um banco de dados. Vamos explorar um pouco as camadas que um sistema pode ter.

Camadas

Em um sistema com boa arquitetura encontramos algumas divisões lógicas que visam facilitar a manutenção e adição de novos recursos. Essas camadas podem ser vistas na Figura 1.

 

Figura 1. Camadas lógicas de um software

 

Para tornar a explicação sobre as camadas mais intuitiva quero que imagine seu sistema. Com toda certeza nele você possui um formulário de cadastro.  O seu formulário representa a camada de apresentação do seu sistema, isto porque é nela que os dados são apresentados. Se seu sistema é cliente/servidor, a sua camada de domínio, de base dados e até mesmo serviços podem ser representadas pelos  Data Modules existentes e seus componentes de acesso ao banco de dados. Por último temos a camada global que pode ser representada pelo seu conjunto de funções e procedimentos públicos.

Continuando com o paralelo a um sistema comum, desenvolvido por um programador Delphi,  nos formulários nós fazemos acesso direto aos Data Modules, aos ClientDataSets, geramos SQL, tudo sem preocupação alguma, ou seja, nós misturamos o que seriam nossas camadas sendo que o correto é separar as camadas.

Quando essas camadas se misturam é dito que existe um acoplamento entre elas. No momento que você insere código SQL em evento OnClick de um botão o acoplamento foi realizado. Seu formulário que é sua camada de apresentação, está fazendo acesso direto aos recursos do que seria sua camada de dados. Isso impede a reutilização da lógica contida no formulário. Tudo isso dificulta a manutenção do seu sistema porque você terá SQL espalhado por todo código e não apenas centralizado em uma área.

Outra prática que é muito comum é de se criar os eventos e dentro deles escrever um código tão longo que para entender o que está sendo feito é quase como ler um livro. Consequentemente a rotina ali dentro poderia ser quebrada em classes ou funções.

Quando uma rotina faz mais do que foi projetada a fazer é dito que existe uma baixa coesão nela. A baixa coesão é outro problema para a boa manutenção do seu software. Então, como podemos separar as camadas sem, contudo uni-las? Pensando nessa solução alguns arquitetos de software criaram os padrões de projeto. Os padrões são de uma forma simplificada, como uma receita de bolo a ser seguida. Eles expõem o problema e mostram como solucioná-lo.

O problema apresentado neste artigo é como separar a interface do sistema do restante da aplicação. Como torná-la independente. A solução já existe, foi desenvolvida na forma de um padrão de projeto chamado MVC – Model View Controller, este é o foco do nosso artigo.

 

Utilizando o  padrão em um exemplo

Nosso primeiro aplicativo de exemplo será simples, porém irá mostrar como iniciar o desenvolvimento utilizando o padrão MVC e fazer uso de interfaces.

Constará apenas de uma tela principal que irá chamar um formulário que permite ao usuário realizar multiplicações. Aqui utilizo o Delphi 2007, contudo, o exemplo pode ser reproduzido também no Delphi 5, 6, 7, 2005 e 2006 sem problema algum e para iniciarmos, inicie um novo projeto Win32.

Para separar a camada de apresentação o MVC cria três partes distintas, o Model, a View e o Controller.  Podemos defini-los da seguinte forma:

·         Model – É a representação da informação que a aplicação utiliza, que no nosso exemplo é o cálculo de multiplicação e os números que serão calculados.

·         View – É a representação gráfica do Model. Por exemplo, um formulário expondo as informações de um cliente. Uma View está sempre ligada a um model e sabe como exibi-lo ao usuário. E para um determinado Model podem existir várias views. Além disso também pode ser composta por várias Views. Aplicando isso ao exemplo, a view é nosso formulário que irá permitir ao usuário digitar o valores e efetuar sua multiplicação. 

Controller – É responsável em mapear as ações do usuário em ações do sistema, por exemplo se um botão ou item de menu é clicado é ele que deve definir como a aplicação responderá. No nosso exemplo é o controller que irá fazer com que ao clicar no botão “calcular” o cálculo seja feito.

 

Colocando a mão na massa

Vamos iniciar criando as partes básicas definidas pelo padrão, o Model, a View e o Controller. Adicione uma unit ao projeto renomeando-a para “MVCInterfaces.pas”. Nela adicione as seguintes interfaces, conforme listagem Listagem 1.

 

Listagem 1. MVC

type

  TModelChangedEvent = procedure of object;

 

  IModel = interface

    ['{FDF18F94-0430-4C48-BE64-F4516C4C1011}']

    procedure Initialize;

    function GetOnModelChanged: TModelChangedEvent;

    procedure SetOnModelChanged(value:

      TModelChangedEvent);

    property OnModelChanged: TModelChangedEvent read

      GetOnModelChanged write SetOnModelChanged;

  end;

 

  IView = interface

    ['{A1F411E9-294D-444D-9D5B-1D6AC9988819}']

    procedure Initialize;

  end;

 

  IController = interface

    ['{E4BD8853-F6C8-4BD4-B19D-D70B156BD712}']

    procedure Initialize;

  end;

 

Como já foi dito, o Model é nossa regra de negócio, ou seja, nosso cálculo de multiplicação. Existem algumas formas de se implementar o MVC, variando de acordo com o entendimento do desenvolvedor. Em sua forma conceitual um Model possui uma referência à View. Neste exemplo não vejo a necessidade disso, já que o Model aqui é a regra de negócio em si.

Em sistemas mais complexos isso pode até fazer sentido por que o Model poderá encapsular várias regras e será um encapsulamento para elas. O que quero dizer é que a parte chamada Model do MVC nem sempre é diretamente uma classe da nossa camada de domínio. Isso significa que a classe TAluno pode conter rotinas e/ou outras classes que têm relação com TAluno, como por exemplo, TCurso e métodos para matrícula.

Adicione uma nova unit ao projeto, salvando-a como “Multiply.pas” e adicione ao uses da interface a Unit MVCInterfaces. Crie uma nova classe conforme Listagem 2.

 

Listagem 2. Model

type

  TModelMultiply = class(TInterfacedObject, IModel)

  private

    FValue1: integer;

    FValue2: integer;

    FOnModelChanged: TModelChangedEvent;

    FSolution: integer;

    procedure SetValue1(const Value: integer);

    procedure SetValue2(const Value: integer);

    function GetOnModelChanged: TModelChangedEvent;

    procedure SetOnModelChanged(value:

      TModelChangedEvent);

    procedure Initialize;

    procedure SetSolution(const Value: integer);

  public

    constructor Create; reintroduce;

"

A exibição deste artigo foi interrompida :(
Este post está disponível para assinantes MVP

 
Você precisa estar logado para dar um feedback. Clique aqui para efetuar o login
Receba nossas novidades
Ficou com alguma dúvida?