Técnico

Refatorando o ModelLocator do Cairngorm – Parte III

Essa é a terceira e última parte da série de artigos sobre a refatoração do ModelLocator do Cairngorm.

Muito obrigado pelo pessoal que veio acompanhando, se interessando e mandando e-mail para discutir suas soluções de implementação.

Como visto no post anterior, vamos hoje liberar o código-fonte completo da refatoração para que vocês possam entender melhor tudo que foi feito e dito, como os padrões de projeto apresentados foram aplicados e principalmente, começar a implementar suas próprias soluções em seus projetos que utilizam o framework Cairngorm.

Você pode encontrar os posts anteriores nos links abaixo:

Refatorando o ModelLocator do Cairngorm – Parte I
Refatorando o ModelLocator do Cairngorm – Parte II

Primeiramente vamos ver como ficou o ModelLocator da aplicação. Atente a como o Domain Model esta sendo inicializado e sua referência injetada no Presentation Model da view principal da aplicação:

 

public static function getInstance():ModelLocator
{
if( instance==null)
{
instance = new ModelLocator();

/**
* O Domain Model e o Presentation Model principal
* são instanciados no momento que nosso ModelLocator
* também é instanciado
*/
instance.agendaModel = new AgendaModel();
instance.mainPM = new MainPM(instance.agendaModel);
}
return instance;
}

 

Construtor do nosso Domain Model (AgendaModel.as), inicializando nossos Presentation Models:

 

/**
*
* @param pAgendaModel – Domain Model da aplicação
* @return
*
*/
public function MainPM(pAgendaModel:AgendaModel)
{
// Recebe instância do Domain Model da aplicação
agendaModel = pAgendaModel;

// Inicializa Presentation Models
contactListPM = new ContactListPM(agendaModel);
contactDetailsPM = new ContactDetailsPM(agendaModel);
}

 

A view principal da aplicação (AgendaProject.mxml) recupera a instância do ModelLocator:

 

/**
* Recuperando a instância do ModelLocator.
* Repare como a DI é usada, com a injeção dos
* Presentations Models em suas respectivas views.
*/
[Bindable]
public var appModel:ModelLocator = ModelLocator.getInstance();

 

Em seguida injeta os Presentation Models nas suas views internas:

 

 

 

 

Repare que o ModelLocator está sendo usado para recuperarmos os modelos da aplicação e não como nosso modelo em si.

Agora vamos ver como nossa aplicação esta acessando nosso modelo para fazer, por exemplo, uma remoção de um contato da agenda:

 

/**
* Remove contato através da chama ao método deleteContact(),
* que está presente no Presentation Model da view.
*/
private function deleteConfirmationAnswer(pEvt:CloseEvent):void
{
if(pEvt.detail == Alert.YES)
{
contactDetailsPM.deleteContact();
clearContact();
}
}

 

Não estamos removendo um item de uma coleção definida no ModelLocator (como estamos acostumados a ver no geral), na realidade não precisamos do ModelLocator daqui pra frente, uma vez que nosso modelo já foi recuperado ao inicializarmos a aplicação, tudo que precisamos com relação ao modelo está agora presente nos Presentation Models e no Domain Model da aplicação.

A chamada do método de remoção de contato visto acima, resulta no disparo de um evento que por fim vai realizar a seguinte operação:

 

public function execute(event:CairngormEvent):void
{
var contactEvt:ContactEvent = event as ContactEvent;
agendaModel.removeContact(contactEvt.contact);
}

 

O método que remove o contato, está presente em nosso Domain Model (AgendaModel.as), conforme abaixo:

 

/**
*
* @param pContact – Contato a ser removido da coleção
*
*/
public function removeContact(pContact:Contact):void
{
var i:int = contactsCollection.getItemIndex(pContact);
contactsCollection.removeItemAt(i);
}

 

Abaixo, temos o datagrid da view “AgendaList.mxml”, que lista nossos contatos. Repare no dataprovider. Normalmente temos nesse momento uma dependência direta com o ModelLocator, mas na nossa implementação temos uma dependência com o modelo da view. Faz sentido agora !?!? rs

 

 

 

 

 

 

 

A aplicação de exemplo é extramamente simples, não teve nenhuma preocupação com suas funcionalidades, mas buscou demonstrar de forma objetiva e direta como implementar os padrões Presentation Model e Domain Model juntamente com o ModelLocator do Cairngorm.
Espero ter contribuido para que vocês possam buscar suas próprias soluções de implementação e que com isso possam alcançar um código mais maduro em suas aplicações.

Como prometido, o download do source pode ser feito aqui.

Fico à disposição para discussões, dúvidas e opniões.

Até a próxima pessoal!

8 Comments

  • Anderson disse:

    Muito bom a conclusão da série! =D

    Só não entendi uma coisa: no meu Presentation Model, quando crio um novo evento, ao invés de chamar o método “dispatch” (não estou utilizando o Cairngorm – http://clockobj.co.uk/2007/10/17/simplified-cairngorm-easy-mvc-for-adobe-flex/) eu faço uma chamada ao dispatchEvent do meu PM (já que o AbstractPresentationModel herda de EventDispatcher). O meu evento está com bubbles == true e o meu systemManager que o escuta (ou pelo menos deveria), só que nada acontece.

    Abraços!

  • Anderson disse:

    Eu não poderia colocar uma referência ao model no AbstractPM, para não ter que criar um em cada Presentation Model? Ou há algum motivo específico para que isso não tenha sido feito?

  • Pablo Souza disse:

    Olá Anderson,

    A função da nossa classe AbstractPM é forçar o programador a implementar os métodos que a classe definiu, mas não implementou.
    Acho mais adequeado nesse caso, ainda mais por estarmos com uma referência direta ao Domain Model, manter a referência do modelo no Presentation Model principal (MainPM.as), uma vez que cada PM da aplicação pode ter referência a um Domain Model diferente.
    Assim, você estende a classe AbstractPM para definir os comportamentos, e define no Presentation Model qual modelo deve ser utilizado.

    Uma solução melhor talves seria ter uma interface referenciando o modelo na classe AbstractPM.as, e seus domain models podem implementar tal interface.

    Um abraço!

  • Anderson Bueno disse:

    Olá Pablo,

    Queria parabenizá-lo por este tutorial!! Mas eu fiquei com algumas duvidas ao adaptar o meu projeto a este sugerido por você.

    Em primeiro lugar eu uso Module no meu projeto por ser muito grande e tudo referente aos modulos foi centralizando em Um ModuleManeger, queria saber aonde entra esse ModuleManeger? Ele poderia vir a virar um Domain Model?

    E outra duvida é se um Presentation Model pode ter referencia de outros Domain Model?

    Abraço.

  • Pablo Souza disse:

    Olá Anderson,

    Obrigado.

    Faz sentido manter num Domain Model os dados que tiverem relação com todos os módulos.

    Quanto ao Presentation Model ter relação com mais de um Domain Model, não vejo necessidade.
    É preciso avaliar que se uma tela precisa ter acesso a dados que estão em outros contextos (módulos), pode ser
    necessário que tais dados estejam no Domain Model.

    Abraco.

  • Alcelyo disse:

    O material ficou show de bola, mas me tira uma duvida quanto aos remot object onde instancialos, e em q AS posso chamalo para fazer a comunicação com o java? Valeu

  • Pablo Souza disse:

    Ola Alcelyo,

    Mostramos nesses posts como refatorar o ModelLocator do Cairngorm.
    Temos algumas variações e refatorações do ServiceLocator do Cairngorm tambem,
    porem numa implementação padrão os Remote Objects ficariam no Service.mxml
    e a chamada aos métodos do Java (no caso que você citou) ficariam nas suas implementações
    dos Delegates.

    Qualquer dúvida estou a disposição.

    Um abraço!

  • Wagner Ramalho disse:

    Opa pablo,
    Muito bom seus posts… realmente foi de vital importância pro projeto que estou atualmente… mas eu to com dúvida e gostaria de saber se você poderia ajudar…
    Eu quero que o um Presentation Model de um componente meu dispare um evento e que seja disparado na view… por exemplo: LoginEvent.EVENT_LOGIN_FAIL seja disparado no PM… e a view do componente login trate isso… tem como fazer com essa arquitetura ai? quais as maneiras que eu teria pra resolver esse problema ?
    obg

Deixe um comentário

O seu endereço de e-mail não será publicado. Campos obrigatórios são marcados com *

Compartilhe isso: