Você está na página 1de 27

Boas Prticas (http://www.devmedia.com.

br/artigo-clube-delphi-102-aplicacoes-win32-com-mvc/11760) Aplicando MVC em Delphi Aprenda a aplicar este poderoso pattern em suas aplicaes
Neste artigo veremos Padres de Projeto; MVC; Boas Prticas;

UML;

Qual a finalidade? Modelar um cadastro de contato utilizando o padro estrutural MVC como realmente ele deve ser, aplicando padro de projeto Observer. Quais situaes utilizam esses recursos? Mais do que separar em camadas, o MVC deve ser utilizado quando se pretender aumentar o nvel de abstrao de uma aplicao, diminuir o forte acoplamento entre os componentes da mesma, porm mantendo a comunicao entre eles.

O padro de projeto MVC surgiu pela primeira vez em 1979 no projeto Smalltalk na Xerox por Trygve Reenskaug, e na minha opinio foi uma das maiores contribuies na rea do desenvolvimento de softwares de todos os tempos pelo menos para a poca em que surgiu. De l pra c diversas variaes do MVC surgiram e a mais conhecida a MVP (Model View Presenter) que devido a falta de material consistente sobre como o MVC tem que ser, causa grande confuso at em programadores experientes. Nos ltimos anos, temos visto um aquecimento em todas as reas da economia e a rea de TI tem um papel importantssimo nesse crescimento, pois independente do setor todos estaro direta ou indiretamente ligados a ela. Com todo esse crescimento as necessidades tambm aumentam a demanda por softwares de qualidade da mesma forma e a nica coisa que diminui o prazo que j era curto e agora est ainda mais apertado. No h para onde escapar. As empresas de desenvolvimento de softwares tm contratado consultorias especializadas para poder atender a demanda de seus clientes.

Seus softwares, que outrora atendiam, j no atendem mais. Com isso (isso digo por experincia prpria), so apresentados a essas empresas e suas equipes tcnicas, padres e boas prticas de desenvolvimento que eram desconhecidas por eles. Digo isso para poder justificar o porqu de se ouvir falar tanto em padres de projeto, boas prticas, OO, etc. Como disse Steve Jobs certa vez: Voc no pode simplesmente perguntar ao usurio o que ele quer e tentar dar-lhe isso, quando voc conseguir terminar o produto o usurio estar querendo outra coisa. Eu vejo essa mudana de cenrio com bons olhos, alis com timos olhos, pois isso elevar o nvel das empresas brasileiras, de sua equipe e conseqentemente o nvel da populao de TI do Brasil. No podemos ficar fora deste cenrio, por isso veremos neste artigo como introduzir nossas aplicaes feitas em Delphi nesse novo cenrio. Como aplicar em nossas aplicaes essas tcnicas e boas prticas e assim aumentar o nvel de nossas aplicaes? bvio que falar em boas prticas falar de diversas solues reutilizveis para construo de softwares orientados a objetos eficientes e que em uma nica edio no possvel abordar, assim o foco deste artigo ser o pattern arquitetural MVC em conjunto com o padro Observer. Assim vamos ao que interessa. Padres de Projeto O conceito de padro de projeto foi usado pela primeira vez na dcada de 70 pelo arquiteto e urbanista austraco Christopher Alexander. Ele observou na poca que as construes, embora fossem diferentes em vrios aspectos, todas passavam pelos mesmos problemas na hora de se construir. Eram problemas que se repetiam em todas elas e na maioria das vezes numa mesma fase da construo. Foi ai que Christopher resolveu documentar esses problemas e mais do que isso, passou tambm a documentar as solues que eram aplicadas para resoluo destes problemas. Entenda que at agora no h nada de programao ou informtica e sim projetos, plantas, mtricas, definies. Nesse momento surgiam os padres de projetos para a engenharia civil, padres esses que descreviam os problemas recorrentes em um projeto de engenharia e a soluo reutilizvel para este problema. Em seus livros Notes on the

Synthesis of Form, The Timeless Way of Building e A Pattern Language Christopher estabelece que um padro deva ter as seguintes caractersticas:
Encapsulamento; Generalidade; Equilbrio; Abstrao; Abertura; Combinatoriedade.

Ou seja, um padro deve ser independente. Deve permitir a construo de outras realizaes. Deve representar abstraes do conhecimento cotidiano. Deve permitir a sua extenso para nveis mais baixos de detalhe e deve ser relacionado hierarquicamente. E assim, foram definidos os padres para projetos na engenharia civil. Anos mais tarde Erich Gamma, Richard Helm, Ralph Johnson e John Vlissides iniciaram suas pesquisas baseados nos trabalhos de Alexander. Tambm conhecidos como GOF (Gang of Four) eles comearam a descrever e documentar os problemas e solues para desenvolvimento de softwares orientados a objetos e em 1995 lanaram o livro que ser tornou um fenmeno na rea de anlise e desenvolvimento de software: Design Patterns: Elements of Reusable Object-Oriented Software. Neste momento iniciava-se uma nova fase no desenvolvimento de sistemas, pois agora havia um padro a ser seguido, e cada padro apresentando uma soluo que poderia se reutilizada vrias vezes para solucionar aqueles problemas recorrentes no desenvolvimento de software. Os padres GOF,como so conhecidos, se dividem em trs grandes categorias: criacionais, estruturais ecomportamentais somando 23 no total. Os 23 padres do GOF so:
Padres Criacionais Abstract Factory Builder Factory Method Prototype Singleton Padres Estruturais Adapter Bridge

Composite Decorator Faade Flyweight Proxy Padres Comportamentais Chain of Responsability Command Interpreter Iterator Mediator Memento Observer State Strategy Template Method Visitor.

Obviamente que o intuito deste projeto no focar em Padres de Projeto, isso poder ser feito em artigos posteriores onde poderemos demonstrar como aplic-los em Delphi, porm gostaria de rapidamente falar sobre interfaces que so os pilares dos padres de projetos e que por sinal faremos dela, ao programarmos, nosso exemplo MVC. Em OO temos a herana como recurso para reaproveitar cdigos e facilitar a manuteno, mas a herana em algumas linguagens como o PHP restringem-se a uma nica classe. No podemos herdar de duas ou mais classes ao mesmo tempo. H linguagens como o C que permitem o uso de herana mltipla, porm os desenvolvedores do Delphi (pascal) optaram pelo uso de interfaces. Interfaces nada mais so do que uma espcie de regra que a classe que a implementa dever seguir ou ter em sua estrutura. Voltando quela analogia bsica que sempre usamos em OO, uma classe como a planta de uma casa, algo ainda intangvel, no papel e o objeto a casa construda, algo concreto. Assim podemos aqui colocar a interface como um contrato de licitao onde estaro todas as clusulas que ditam as regras e normas para a construo desse objeto. No importa qual construtora ir construir a casa, desde que esta construtora se enquadre nas regras do contrato. Assim podemos crer que a casa ser construda como foi predeterminada. Na prtica podemos criar uma interface em nosso modelo que ter os mtodos que julgamos necessrios para determinada ao e desta maneira toda a

classe que implementar esta interface ter estes mtodos e os implementar de acordo com a sua necessidade. A vantagem que uma classe pode implementar mais de uma interface e com isso manter um relacionamento um com mais de uma estrutura MVC Model View Controller Separar as aplicaes em camadas no algo novo no meio de desenvolvimento de softwares. A busca por aplicaes de fcil manuteno inspirou grandes mentes a desenvolver tcnicas e modelos que auxiliam nesta tarefa. Porm de incio quero deixar claro um fato importantssimo: separar uma aplicao em camadas pura e simplesmente no significa que voc esta aplicando MVC. A arquitetura em camadas utilizada para separar responsabilidades em uma aplicao. Este tipo de aplicao se popularizou muito no incio da dcada de 90 com o boom da internet, porm muitos desenvolvedores ainda no conhecem a tcnica a fundo, devido a escassez de documentao eficiente sobre este padro arquitetural. Junto com a disseminao da arquitetura em camadas, veio o ressurgimento do modelo MVC criado em Smalltalk e que traz simplicidade e coerncia View. Tanto o modelo em camadas quanto o MVC so padres arquiteturais muito similares e que passaram a ser continuamente confundidos. MVC e desenvolvimento em camadas so abordagens diferentes que podem ser ou no aplicados em conjunto. A abordagem do desenvolvimento em camadas visa organizar e manter os componentes separados baseados em algum critrio que na maioria das vezes a funo que este componente desempenha. Separando os componentes em grupo, conseguimos diminuir o acoplamento entre eles isolando assim a mudanas que so realizadas em uma camada para que no afetem as outras. Uma aplicao Win32 desenvolvida 100% orientada a objetos poderia sem problema algum ser separada em camadas para facilitar o desenvolvimento e manuteno. Observe o diagrama da Figura 1 e tente identificar as camadas. Nota: O emprego correto do termo componente utilizado para descrever um artefato de software que pode ser uma classe, objeto, camada, etc. Ns, que estamos

familiarizados com a VCL do Delphi, tendemos a associar o termo componente com os controles utilizados na VCL. Estes ltimos so identificados pelo termo controle. Assim, estarei aqui me referindo a artefatos de software como componente.

Figura 1. Modelo UML

A separao em camadas no se d pela separao fsica das classes, mas sim pela separao lgicade acordo com um critrio definido pelo analista/arquiteto de sistemas. No caso exposto na Figura 1 as camadas (lgicas) esto divididas segundo suas responsabilidades, na Figura 2 isso fica mais claro. Observe:

Figura 2. Modelo Separado em Camadas

Bem se separar em camadas no MVC ento o que ? Digamos que temos uma aplicao onde aplicamos a separao em camadas de acordo com a responsabilidade de cada componente. Se estes componentes esto separados, ou melhor, desacoplados ento temos que de alguma forma fazer com que se comuniquem, mas que continuem independentes em sua essncia. Isso realmente seria excelente, o famoso cada um na sua, mas com alguma coisa em comum. Este tipo de abordagem torna o modelo muito eficiente. Mas como manter as interfaces grficas atualizadas refletindo o atual estado do modelo com quem ela interage? Deu para perceber com o questionamento que entre outras coisas o modelo MVC tem a ver com sincronizao entre os componentes? As interfaces grficas geralmente exibem o estado dos objetos de uma aplicao, e isso deve ser feito em tempo real. Qualquer alterao no objeto dever ser refletida na hora, na View. Outro ponto que o usurio da sua aplicao dever interagir com o seu modelo de negcio e ele o vai fazer atravs da View. Da, vemos importncia do MVC aplicado a softwares desenvolvidos em Delphi, pois por ser RAD o Delphi nos trs uma produtividade muito grande, porm isso tem um lado ruim. Se cada controle em um form for responsvel por invocar mtodos nos objetos o cdigo tende a ficar repetitivo e difcil de manter. Diversas regras e rotinas podero estar contidas dentro dos

botes e demais controles no formulrio. Isso torna o cdigo poludo, de difcil manuteno e altamente acoplado, pois suas regras de negcio esto dispersas entre o modelo e a View. neste cenrio que entra o MVC, para alm de termos as camadas com suas responsabilidades, temos os componentes da aplicao interagindo entre si em tempo real onde o modelo passa a ser ativo notificando as views inscritas nele. Este modelo consiste no bom uso integrado de alguns Design Patterns (Padres de Projeto) clssicos, como Observer e Strategy. Se buscarmos na internet ou em livros o significado de MVC, vamos encontrar algo como:

Model-view-controller (MVC) um padro de arquitetura de software. Com o aumento da complexidade das aplicaes desenvolvidas torna-se fundamental a separao entre os dados (Model) e o layout (View). Desta forma, alteraes feitas no layout no afetam a manipulao de dados, e estes podero ser reorganizados sem alterar o layout. O model-view-controller resolve este problema atravs da separao das tarefas de acesso aos dados e lgica de negcio, lgica de apresentao e de interao com o utilizador, introduzindo um componente entre os dois: o Controller. MVC usado em padres de projeto de software, mas MVC abrange mais da arquitetura de uma aplicao do que tpico para um padro de projeto.

No modelo em camadas comum dividir a aplicao em: apresentao (interface), domnio (Model) e acesso a dados. Podemos dizer que a, grosso modo, em MVC a camada de apresentao tambm separada em View e Controller.

Nota do DevMan Em MVC geralmente as camadas so descritas assim:

Model: classes de domnio no seu modelo de negcio. Representa o estado do sistema. View: parte exposta, renderiza o Model em uma forma especifica para interao (WebForm, Form, HTML, etc.) Controller: Processa e responde a eventos, geralmente aes do usurio, invocando alteraes no Model.

Geralmente o fluxo de iterao entre os componentes no MVC se d na maioria das vezes da seguinte maneira: O usurio interage com a interface de alguma forma, clicando em um boto da View (no nosso caso Form). O Controller quem recebe o estimulo provocado na View, acessando o Model, e invocando um mtodo ou atualizando de alguma forma. O Model por sua vez notifica a(s) Viewsinscritas neles para receber as atualizaes. A View recebe a notificao e se encarrega de atualizar seus controles conforme a necessidade. Os diagramas das Figuras 3 e 4 expressam a seqncia dos acontecimentos.

Figura 3. Usurio interage com a view e o controller repassa ao modelo

Figura 4. O modelo notifica e View que atualizada

O estmulo vindo do usurio (ou de outro componente se voc est usando MVC fora de uma interface grfica) vai para o Controller que o componente com inteligncia o suficiente para saber qual operao invocar no Model. A operao invocada pode efetuar a mudana de estado no Model. Como a View observa este, assim que a mudana de estado for realizada ela atualizada. Assim vemos que o diferencial do MVC para o modelo separado em camadas que o primeiro foca em mais do que separar em camadas, mais cuida da iterao entre os componentes que fazem parte do modelo.

MVC no Delphi Vamos ento aplicar o conceito MVC em um pequeno exemplo feito em Delphi. Nosso exemplo focar em criar o modelo MVC. No prximo artigo daremos seqncia ao exemplo adicionando a camada de persistncia e concludo assim nosso exemplo. Como visto anteriormente, um dos desafios da arquitetura em camadas justamente manter a camada de apresentao sincronizada com a camada de negcio. No MVC isso no um desafio e sim parte do modelo e isso feito aplicando o padro de

projeto Observer. O padro Observer define uma dependncia um-para-muitos entre objetos de forma que se um mudar seu estado, todos os objetos dependentes sero notificados e atualizados automaticamente. [GoF]. Este padro muito freqente em projetos orientados a objetos. No Delphi este padro est presente na notificao entre os componentes no form designer, quando um componente removido ou inserido.

Figura 5. Modelo do padro Observer

Em nosso exemplo em Delphi faremos uso do padro Observer, ento vamos a ele.

Nota: O exemplo ser desenvolvido utilizando a verso 2006 do Delphi, porm com exceo da modelagem UML feita no Together o exemplo poder ser construdo com qualquer verso do Delphi a partir da verso 3.

No Delphi 2006 crie uma nova aplicao Win32 e salve-a em uma pasta padro. Renomeie o formulrio para FrmMenuPrincipal.dpr. Ainda neste projeto adicione uma nova Unit onde iremos criar nosso modelo padro, ou seja, nossa classe bsica assim

como as interfaces necessrias ao padro Observer. Salve-a como BaseModel.pas. A Figura 6 demonstra nosso modelo de classe.

Figura 6. Modelo de classe

As interfaces IObserver e IObservable so requeridas para o padro Observer. TBaseObject ser o objeto base para todas as outras classes presente em nossa aplicao. A interface IController apenas uma sugesto que eu costumo utilizar para criar um repositrio de Controller. evidente que utilizando o Together aps fazermos a modelagem UML no h a necessidade de gerarmos o cdigo, pois o mesmo gerado automaticamente, porm possvel codificar manualmente para aqueles que possuem outras verses do Delphi. Veja a Listagem 1 que contm todo o cdigo do diagrama gerado na Figura 6. Assim na Unit BaseModel.pas digite o cdigo da Listagem 1.

Listagem 1. Declarao das Interfaces IObservable = interface; IObserver = Interface ['{65032CAD-7441-4754-A860-BFECE58D50EF}']

procedure Update(Observable: IObservable); end; IObservable = Interface ['{637D22E1-45BD-479E-96D3-39F6DD94234B}'] procedure Atach(Observer: IObserver); procedure Desatach(Observer: IObserver); procedure Notify; end; TBaseObject = class; IController = Interface ['{2C5753F9-473F-4D22-9FEA-28E2B84C629E}'] procedure Save; function Find(ID: String): TBaseObject; function New: TBaseObject; end;

No cdigo da Listagem 1 temos a declarao das interfaces requerida pelo padro Observer. A interface IObserver possui apenas um mtodo (Update), que dever ser implementado por toda a classe que quiser ser um observador em nosso modelo. Isso por que o observado quando for notificar os observadores ir invocar o mtodo Update da o porqu deste mtodo estar presente ai. O parmetro do tipo IObservable serve para que o observador possa saber por quem ele foi notificado. Observe que na linha um temos apenas um hint da interface IObservable. Isso necessrio, pois o compilador Delphi Top-Down e a interface IObservable declarada abaixo da interface IObservere como o mtodo Update possui um parmetro do tipo IObservable temos que lanar mo da tcnica de forward. O mesmo ocorre na declarao de TBaseObject. Para inclu-las basta pressionar Ctrl + Shift + G dentro da declarao de sua interface. A interfaceIObservable possui 3 mtodos, isso porque qualquer objeto que possa ser observado em um modelo dever ter um canal para que os observadores possam se inscrever para serem notificados (Atach), da mesma forma os observadores devem possuir uma maneira de se retirar da lista de notificaes (Desatach) e por fim um mtodo para notificar os observadores que algo aconteceu. A interfaceIController como citei anteriormente apenas uma sugesto para que possamos criar uma coleo deControllers para futura manipulao.

Bem interfaces so apenas contratos, regras, declaraes que precisaro ser implementados por uma classe concreta. Como no MVC nossos Models so Observadores ento nossa BaseObject quem vai implementar a interface IObservable e nossas views a interface IObserver. Assim vamos ao cdigo da Listagem 2 que descreve a nossa BaseObject ainda na Unit BaseModel.

Listagem 2. Declarao da Classe BaseObject TBaseObject = class(TInterfacedObject, IObservable) private FObservers: TInterfaceList; FID: String; procedure SetID(const Value: String); protected public constructor Create; destructor Destroy; override; procedure Atach(Observer: IObserver); procedure Desatach(Observer: IObserver); procedure Notify; published property ID: String read FID write SetID; end;

Na Listagem 2 temos a declarao da classe que servir de base para todas as demais em nosso modelo. A primeira considerao a fazer em relao ao fato de herdarmos de TInterfacedObject. Isso uma condio para todas as classes que iro implementar uma ou mais interfaces no Delphi, isso se deve ao fato desta classe j implementar 3 mtodos essenciais para se trabalhar com interfaces. So eles: QueryInterface, _AddRef e _Release. Existe ainda outras classes que implementam estes trs mtodos e, portanto poderiam ser usadas aqui tambm, como TContainedObject, TInterfaceList eTInterfacedPersistent, porm a classe TInterfacedObject a mais bsica de todas elas. Seguindo adiante temos na linha 3 um atributo privado FObservers que servir como continer para todos os observadores que se inscreverem em um de nossos modelos. O campo FID e o mtodosetId so resultado da implementao da propriedade ID. Na

seo pblica da nossa classe temos alm do construtor e destrutor a declarao, para posterior implementao, dos mtodos presentes na interface IObservable (Atach, Desatach e Notify). Vale ressaltar aqui que somente poder ser passado como parmetros para os dois primeiros mtodos objetos produtos de uma classe que implemente a interface IObserver, ou seja, estamos garantindo que somente observadores se inscrevam na lista para serem notificados e se so observadores logo possuem sem dvida nenhuma o mtodo update que ser invocado quando a notificao for disparada. Na Listagem 3 podemos conferir a implementao dos 5 mtodos presentes em nossa TBaseObject.

Listagem 3. Implementao dos Mtodos procedure TBaseObject.Atach(Observer: IObserver); begin FObservers.Add(Observer); end; constructor TBaseObject.Create; var GID: TGUID; begin FObservers := TInterfaceList.Create; if CoCreateGuid(GID) = S_OK then FID := GUIDToString(GID); end; procedure TBaseObject.Desatach(Observer: IObserver); begin FObservers.Remove(Observer); end; destructor TBaseObject.Destroy; begin FreeAndNil(FObservers); inherited; end; procedure TBaseObject.Notify; var Obs: IInterface; begin for Obs in FObservers do IObserver(Obs).Update(Self);

end;

Na Listagem 3 temos a implementao dos mtodos outrora definidos na interface IObservable alm do destrutor e construtor. O mtodo Attach recebe como parmetro um objeto do tipo IObserver, ou seja, todo objeto que implemente a interface IObserver poder ser passado como parmetro e isso excelente, pois se uma classe que hoje no um observador amanh poder ser, bastando para isso implementar a interface IObserver. E como uma classe pode implementar uma ou mais interfaces no corremos o risco dela j estar implementando uma interface como ocorre no caso da herana. Veja na terceira linha que apenas adicionamos o objeto passado como na lista de observadores. Na seqncia temos a implementao do construtor da nossa classe. Nele instanciamos a classeTInterfaceList que ir funcionar como repositrio de observadores e em seguida geramos uma novaGUID e associamos a propriedade ID do nosso objeto, assim garantimos um identificador nico para cada objeto que for criado em nosso modelo de dados.

TGUID um record no Delphi utilizado para representar um GUID (Global Unique Identifier). A declarao de uma interface pode conter um GUID que declarado como uma cadeia de caracteres entre colchetes da seguinte forma: [{xxxxxxxx-xxxx-xxxxxxxx-xxxxxxxx}] onde cada x um digito hexadecimal 0 F. Voc pode gerar suas GUIDs no Delphi pressionando Ctrl + Shift + G no Code Editor.

O cdigo do mtodo Desattach apenas remove o objeto referido como parmetro da lista de notificaes, assim este objeto no ser mais notificado. No destructor apenas destrumos o objetoTInterfaceList para, por fim, chegarmos ao to aguardado mtodo Notify. Este ser o mtodo chamado toda fez que o estado no objeto em questo for alterado, ou seja, ao menor sinal de iterao com o objeto o mtodo Notify dever ser invocado e tem um motivo bvio para isso.

Observe na Listagem 3 que nosso cdigo comea fazendo um loop com o mtodo for in em nossa lista de observadores e para cada item da nossa lista invocamos o mtodo update e passamos o prprio objeto como parmetro para que o observador saiba por quem ele foi notificado. Assim cabe agora ao observador, que no MVC ser a View, tomar a providncia necessria para atualizar os dados do modelo na View. E isso que veremos mais a frente. Com nossa classe base pronta vamos a criao da nossa classe de negcio que ser a classe TClienteque herdar de nossa BaseObejct j nascendo com a possibilidade de ser observada por um observador. Assim ainda em nosso projeto no Delphi adicione mais uma Unit, salve-a comouCliente.pas e nela declare o cdigo da Listagem 4.

Listagem 4. Declarao da Classe Cliente uses BaseModel; type TCliente = class(TBaseObject) private protected public procedure Salvar; function Buscar(Codigo: String): TCliente; published property Nome: String; property Email: String; property Telefone: String; end;

O cdigo da Listagem 4 mostra a nossa classe cliente ainda sem a implementao dos mtodos eproperty. Para gerar a implementao basta pressionar Ctrl + Shift + C. O cdigo gerado nada mais do que a implementao das property o que dispensa comentrio e mais a implementao dos mtodos Salvar, Deletar e Buscar. Esses mtodos so apenas ilustrativos e esto ai para demonstrar a mudana de estado do objeto, e como estamos falando sobre MVC a cada alterao no estado do objeto os observadores, nesse caso sero as views, devero ser notificadas.

O mtodo salvar, quando chamado, dever persistir o objeto em questo no banco de dados. No escopo deste artigo tratar de persistncia, sendo assim alm de invocar o mtodo notify na implementao do mtodo salvar voc invocaria sua classe de persistncia e solicitaria a ela que persistisse seu objeto. J o mtodo Buscar servir para carregar na classe informaes de um objeto especfico. Como em OO temos o conceito de Object ID, ou seja, cada objeto em seu modelo dever possuir um identificador nico, passamos apenas o ID do objeto para que possa ser carregado no mesmo os dados referente ao objeto possuidor do ID. Como dito acima, no teremos aqui a implementao do mtodo como um todo, pois isso tambm seria funo da classe de persistncia, porm o mtodo notify ser invocado para notificar os observadores que os dados do modelo foram alterados. Sendo assim na implementao deste dois mtodos apenas invoque o mtodo notify. Com isso conclumos nosso Model. O mesmo j pode ser persistido e notificado aos observadores caso seu estado seja alterado. Passemos ento a criao da nossa classe de controle.

Controller Ainda neste mesmo projeto, adicione uma nova Unit e salve-a como ClienteController.pas. nestaUnit que iremos criar a classe de controle para iterar com nosso modelo. Assim, esta classe de controle esta apresentada na Listagem 5.

Listagem 5. Classe ClienteController TClienteController = class(TInterfacedObject, IController) private FModel: TCliente; class var Finstance: TClienteController; constructor PrivateCreate; protected public class function GetInstance: TClienteController; constructor Create; destructor Destroy; override; procedure Save;

function Find(ID: String): TBaseObject; function New: TBaseObject; published property Model: TCliente read FModel; end; implementation uses SysUtils; constructor TClienteController.PrivateCreate; begin inherited Create; end; constructor TClienteController.Create; begin raise Exception.Create('Para Obter um ClienteController Invoque o GetIntance'); end; destructor TClienteController.Destroy; begin inherited; end; function TClienteController.Find(ID:String): TBaseObject; begin Result := FModel.Buscar(ID); end; class function TClienteController.GetInstance: TClienteController; begin if not Assigned(Finstance) then Finstance := TClienteController.PrivateCreate; Result := Finstance; end; function TClienteController.New: TBaseObject; begin FModel := TCliente.Create; Result := FModel; end; procedure TClienteController.Save; begin FModel.Salvar; end; end.

Metodo

Se voc atentou a definio do padro MVC e a imagem da Figura 3 ir perceber que a funo doController exatamente mapear as aes do usurio na View e ter inteligncia suficiente para saber qual mtodo invocar no modelo. Por isso muito comum que voc encontre no controller os mtodos de CRUD, para que o usurio atravs da View possa invocar mtodos para manipular um determinado Model. Assim comeamos a declarao do nosso Controller implementando a interfaceIController e desta maneira temos em Controller os mtodos presentes na interface IController. J podemos ento permitir a View, atravs do Controller, criar um novo Objeto, Buscar um Objeto e salvar alteraes no modelo. Porm vamos atentar para o fato de, se o Controller tem a funo que tem, no justifica ter num projeto dois ClienteController se o usurio s poder manipular um cliente por vez (pelo menos essa e a minha abordagem). Assim vamos aplicar a nossa classe ClienteController o padro de projeto Singleton. Temos os mtodos necessrios para poder implementar o Singleton. Uma varivel de classe para guardar a instncia quando criada, um mtodo de classe (GetInstance) para retornar uma instncia deTClienteContoller e um construtor privado para construir nosso objeto. Esse construtor privado, pois o construtor pblico foi invalidado, observe na linha 26. Se algum tentar instanciar um objeto do tipo TClienteController ir receber um erro. Desta forma garantimos que s teremos um nico objeto instanciado em nossa aplicao, e como eu posso garantir isso? Simples. Como a nica maneira de instanciar um Objeto TClienteController atravs do mtodoGetInstance, ento nele que fazemos a verificao para saber se j no h um objeto instanciado. Caso no haja um objeto instanciado ento criamos um e o armazenamos na variavl FInstance. Da prxima vez que o mtodo GetInstance for chamado no ser criado um novo objeto apenas retornado o objeto que j existe. O padro de projeto Singleton assegura que haja somente uma instncia de uma classe, e fornece um ponto de acesso global para acess-la [GoF]. Utilizado em situaes onde queremos garantir que s haver um e somente um objeto deste tipo na aplicao. Isto feito invalidando o construtor da classe e criando um mtodo de classe que retorne uma instancia deste objeto.

H apenas uma ressalva aqui. Como disse no incio do artigo que este exemplo poderia ser feito com verses do Delphi posteriores a 3, ento aqueles que estiverem com verses anteriores a 2006 devero substituir a class var por uma varivel global, pois verses anteriores a 2006 no suportamclass var. Continuando no cdigo da Listagem 5 temos os mtodos que mapearo a ao do usurio na Viewpara o Model. Assim fica simples entender o que ser feito na implementao de cada mtodo. Mais abaixo mostrado a implementao do mtodo Save, ele invoca o mtodo salvar no modelo, que se encarrega que persistir os dados (neste artigo no abordamos isso) e notificar a View. Assim quando o usurio clicar no boto salvar o modelo mudar de estado e a View receber a notificao e se atualizar. Isso ser feito adiante. Em seguida faz a mesma coisa porm com o mtodo Buscar. Observe que sempre fazemos a chamada de FModel que a propriedade do prprio Controller. porm uma propriedade somente leitura. Isso para garantir que ningum ira passar um Model para o Controller garantindo assim que a nica maneira de um Model ser associado ao Controller e atravs do mtodo New, e isto que mostra nas seguintes.

Cliente View Vamos adicionar ao nosso projeto mais um formulrio. Salve-o como uFrmCliente.pas e renomeie-o para FrmCliente. Relembrando, a funo da View permitir que o usurio interaja com o modelo com suas aes sendo mapeadas pelo Controller. Sendo assim temos que ter em nossa Viewcontroles visuais para podermos valorar nosso Model. O principal ser feito agora. Como no padro MVC a View observa o modelo ento temos que transformar nossa View num observador e faremos isso implementando a interface IObserver na nossa classe TFrmCliente. Desta forma o formulrio de cliente obrigado a implementar o mtodoUpdate, que extremamente importante, pois este mtodo que ser responsvel por atualizar aView. Observe a Listagem 6, ela mostra a

como fica a declarao da classe cliente com a interface implementada e os demais mtodos requeridos.

Listagem 6. Implementao da interface IObserver


TFrmCliente = class(TForm, IObserver) private FController: TClienteController; public constructor Create(AOwner: TComponent; Controller: TClienteController);reintroduce; procedure Update(Observable: IObservable); end;

Em primeiro lugar notrio a presena do mtodo update, isso porque implementamos a interfaceIObeserver. Com isso nosso form, ou melhor, View tem que poder ser atualizado com o mtodoupdate. Lembre-se que em nosso Model a cada mudana de estado invocamos o mtodo Notify e este por sua vez faz um loop na lista de observadores e chama para cada um o mtodo update. Ainda no cdigo da Listagem 6 temos uma atributo do tipo TClienteController, isso para podermos guardar a referncia do Controller que a View est se comunicando. Toda View tem suas aes, ou melhor, aes do usurio mapeadas para um Controller da o motivo de ainda na Listagem 6 nos reescrevermos o construtor do nosso formulrio. Observe que o construtor agora pede dois parmetros: o owner que j padro para todo componente e agora tambm pede um Controller, assim garantiremos que ao criar uma View j teremos um Controller associado a ela. E para que isto? Tenha sempre em mente que as aes do usurio mapeadas pela View devem ser enviadas ao Modelatravs do Controller, por isso esta condio de s criarmos uma View com um Controllerpreviamente criado. A implementao dos mtodos explica-se por si s. Observe a Listagem 7.

Listagem 7. Implementao dos Mtodos da View


constructor TFrmCliente.Create(AOwner: TComponent; Controller: TClienteController);

begin inherited Create(AOwner); FController := Controller; end; procedure TFrmCliente.Update(Observable: IObservable); begin EdtID.Text := FController.Model.ID; EdtNome.Text := FController.Model.Nome; EdtEmail.Text := FController.Model.Email; EdtTelefone.Text := FController.Model.Telefone; end;

Veja que no construtor da nossa View ns invocamos o construtor de TForm e passamos para ele oOwner passado como parmetro. O segundo parmetro, o Controller, ns guardamos no Field FController, com isso garantimos que esta View o ser criada se um Controller for passado como parmetro. Na seqncia vemos a implementao do mtodo Update. Observe que a View ao ser notificada atualiza os controles da View repassando para os mesmos os novos dados do modelo. Note bem que os valores so obtido via Controller, porm tambm poderia ser feito fazendo umtypecasting de IObservable para TCliente. Para concluir nossa View vamos a implementao dos eventos clique dos botes novo, pesquisar e salvar. A Listagem 8 se encarrega de exibir os mtodos.

Listagem 8. Implementao dos mtodos


procedure TFrmCliente.BtnNovoClick(Sender: TObject); begin FController.New; FController.Model.Atach(Self); end; procedure TFrmCliente.BtnPesquisarClick(Sender: TObject); begin FController.Model.Buscar(''); end; procedure TFrmCliente.BtnSalvarClick(Sender: TObject); begin FController.Model.Nome := EdtNome.Text; FController.Model.Email := EdtEmail.Text; FController.Model.Telefone := EdtTelefone.Text; FController.Save; end;

Como dito anteriormente o Controller mapeia as aes executadas na View para o Model. E a implementao dos mtodos na Listagem 8 ilustra bem isto. O clique do boto novo invoca o mtodonew do Controller e este por sua vez cria um novo objeto Cliente e o armazena internamente na propriedade Model. Feito isso o prximo passo inscrever esta View onde estamos neste novo modelo para que a mesma possa receber as notificaes necessrias ao longo do ciclo de vida o objeto. O boto pesquisar apenas invoca o mtodo Buscar do modelo que (se tivesse implementao com DAO) configuraria as propriedades do Objeto Cliente com os dados oriundos do banco de dados. Por fim temos o cdigo do clique do boto salvar. Este por sua vez pega os valores dos edits, atribui as propriedades do Model que esta sendo controlado pelo Controller no momento e invoca o mtodoSave. Este mtodo e mapeado para o Model que se encarrega de persistir o objeto e notificar os Observadores. Com isto temos nosso MVC implementado e pronto para uso. Vamos, em carter de teste, invocar nossa View e realizar os testes. Assim no form principal da aplicao coloque um boto para invocar a View Cliente e no evento OnClick insira o cdigo da Listagem 9.

Listagem 9. Chamando a View do Cliente


procedure TForm1.BtnClienteClick(Sender: TObject); var C: TClienteController; begin C := TClienteController.GetInstance; FrmCliente := TFrmCliente.Create(Self,C); FrmCliente.Show; end;

No clique do boto que invocamos a View do cliente ns declaramos uma varivel do tipoTClienteController e Pedimos um Controller para ela, lembrando que o ClienteController umSingleton e como tal s termos um instanciado por vez em

nossa aplicao. Em seguida criamos nossaView do cliente e repare que ao chamar o construtor ele nos pede alm do owner um Controller, e ai que passamos a varivel C com o Controller criado acima. Feito isso exibimos a View com o j conhecido mtodo Show. Rode a aplicao, clique no boto novo e em seguida no boto salvar (Figura 7).

Figura 7. Novo cliente criado e salvo

Veja que nosso MVC j esta em pleno funcionamento. Ao clicar em novo o Controller criou um novo objeto e neste momento j temos um GUID associado a e,le porm como no ouve notificao aView no esta sabendo. Quando chamamos o mtodo salvar a notificao feita a todos os observadores e como nossa View est inscrita na lista a mesma notificada e os dados atualizados naView. E bvio que uma aplicao Stand Alone como esta pode no mostrar todo o potencial deste padro arquitetural, mas experimente chamar outro formulrio e clique em novo. Depois altere os dados no primeiro Form e salve. Voc ir perceber que o segundo Form tambm ser atualizado com os dados do primeiro. A Figura 8 mostra o exemplo citado em funcionamento.

Figura 8. Duas View sendo atualizadas ao mesmo tempo

Concluso O padro MVC muito mais comum na WEB, isso porque fica fcil criar um repositrio deControllers, que ficaria na sesso e assim conseguiria notificar todas as Views. Porm nada nos impede de aplicarmos em aplicaes Win32. Porm h de se ficar claro que no justifica aplicar o padro MVC em uma aplicao Stand Alone como fizemos aqui. Mas imagine este padro aplicado numa Aplicao que tenha um servidor de objetos, COM+ por exemplo. Poderamos ali criar nosso repositrio de objetos e um Controller Singleton para mapear as aes dos usurios. O importante deixar claro que este um padro arquitetural que pode ser, e deve ser aplicado junto com outros padres de projeto, pois como os outros se trata tambm de uma boa prtica de programao. Eu fico por aqui, espero que tenha contribudo com mais este artigo para o nosso aprendizado. At a persistncia.

Rodrigo Carreiro Mouro


Gestor de TI com especializao em gerncia de projetos (PMI) e Governana de TI (ITIL e COBIT) pelo instituto Infnet. Embarcadero MVP e Instrutor certificado pela Borland. Graduando-se em Gesto de TI focada em negcios. Grande entusiasta do desenvolvimento orientado a objetos, padres de projetos,...

17