MVVM_
Implementando o padrão
de projeto MVVM com
O padrão de projeto MVVM
O
MVVM (Model-View-ViewModel) foi divulgado pela primeira vez em 2005 por John Gossman, na época arquiteto da plataforma Silverlight da Micro-soft em seu blog. O mesmo se baseou fortemente no padrão de projeto Presentation Model (muito seme-lhante ao MVP − Model-View-Presenter), divulgado por Martin Fowler em 2004. Verifique o diagrama do padrão MVVM na figura 1.Abaixo o papel de cada camada do MVVM:
view: a representação visual de elementos e
ações que farão a interface com o usuário.
viewmodel: uma classe responsável por conter
o binding (ligação) com os elementos da View. A des-crição real é que a mesma se trata do modelo da tela, representando o estado atual da mesma.
model: referente a um modelo de domínio,
re-presentando o estado atual do mesmo.
O grande diferencial que o MVVM adotou e que o destaca de outros padrões de projeto conhecidos como o MVC, é sua capacidade de separar a camada de apresentação (View) da lógica de apresentação (ViewModel), facilitando a aplicação de testes uni-tários na ViewModel. A ViewModel cria seu próprio
modelo de representação da View, acabando com os acessos diretos à camada Model. As camadas acabam ficando menos acopladas, facilitando a manutenção.
Quando proporcionamos a separação das cama-das, podemos separar as responsabilidades no de-senvolvimento de sistemas, assim decentralizamos as tarefas. Nesse modelo, as interfaces podem ser criadas por designers e o código por programadores.
Graças a sua flexibilidade, o padrão MVVM foi facilmente adaptado às plataformas modernas ba-seadas no modelo Event-Driven-Developer, como WPF (Windows Presentation Foundation), Silverligh e Android.
Saiba como criar um projeto
utilizando o padrão de projeto MVVM
no Android
Android
Binding
View ViewModel
Model Figura 1. Diagrama do padrão de projeto MVVM.
Em um tempo que os principais requisitos são o desenvolvimento de
softwares de forma cada vez mais rápida e produtiva e que ainda
sejam confiáveis e fáceis de manter, possuir uma boa plataforma de
projeto é um diferencial. Apesar do Android prover certas
facilida-des para o facilida-desenvolvedor, nativamente não disponibiliza algumas
implementações como padrão de projeto MVVM, basicamente
res-ponsável por simplificar a amarração entre design e código,
presen-te em outras plataformas como a Silverlight da Microsoft. Para que
possamos adaptar o Android na utilização deste padrão, temos que
nos utilizar de frameworks que no caso deste artigo será o Android
Binding.
Giuliano Bem Hur Firmino | giulianofirmino@yahoo.com.br Especialista em Engenharia de Software pelo Instituto da Computação da Unicamp e certificado pela Sun (SCJP). Atua na área de desenvolvimento de softwares há 11 anos. Com a plataforma JAVA nos ambientes Web, Mobile e Enterprise.
Padrões de apresentação
Abaixo, poderemos verificar os principais pa-drões de projeto voltados à apresentação utilizados no mercado e quais as diferenças comparados ao MVVM.
MVVM x MVC (Model-View-Controller)
O MVC é um padrão de projeto criado em 1979 por Trygve Reenskaug, inicialmente desenvolvido para Smaltalk. O mesmo surgiu com objetivo de me-lhorar a organização do projeto, separando acesso aos dados, regras de negócios e lógica de apresen-tação. Atualmente o mesmo é considerado uma “ar-quitetura padrão” no desenvolvimento de software. Confira o seu diagrama na figura 2.
O MVC se diferencia do MVVM, por conta do li-vre acesso da View a camada Model, o que o torna fortemente acoplado.
MVVM x MVP (Model-View-Presenter)
O MVP foi criado originalmente em 1990 pela Taligent, uma parceira da Apple, IBM e HP. É um padrão de projeto que facilita a automação de tes-tes unitários e separação de conceitos na camada de apresentação. Confira o seu diagrama na figura 3.
O MVP se diferencia do MVVM, por conta da pre-sença da interface que representa a View. Podemos por exemplo desenvolver uma tela em swing e outra em Android e utilizar o mesmo Presenter, bastando implementar a Interface que representa a View, nas diferentes plataformas. Isso não acontece no MVVM, pois o mesmo é amarrado à plataforma/framework.
observer
De acordo com a definição GoF, seu objetivo é “Definir uma dependência um-para-muitos entre
objetos para que quando um objeto mudar de esta-do, todos os seus dependentes sejam notificados e atualizados automaticamente”. Você pode observar o seu funcionamento no diagrama da figura 4.
MVVM x MVP x MVC
View Controller
Model
Figura 2. Diagrama do padrão de projeto MVC. Figura 3. Diagrama do padrão de projeto MVP.
View Presenter
Acoplamento entre View e Model Reutilização do código para N Views Parceria com o padrão Observer
MVVM Não Não Sim
MVP Não Sim Sim
MVC Sim Não Não
Sobre o Android Binding
Android Binding é um framework open-source desenvolvido para a plataforma Android que provê de maneira simples, binding de componentes visuais contidos em arquivos xML. Sua arquitetura foi criada principalmente para ajudar no desenvolvimento de aplicações utilizando o padrão de projeto MVVM.
Para se desenvolver aplicações visuais para An-droid, são necessários classes do tipo Activity, essas classes na arquitetura padrão, detêm muita das res-ponsabilidades do sistema, como controlar o fluxo da aplicação, entradas dos usuários, comunicação com a camada de negócio, entre outros. Ao utilizar o An-droid Binding a responsabilidade das classes Activity, são reduzidas a amarrar as camadas View e ViewMo-del, separando as tarefas e simplificando ainda mais o desenvolvimento para Android.
O projeto de exemplo
Para exemplificar a utilização do padrão de pro-jeto MVVM e algumas das funcionalidades presentes no framework AndroidBinding, vamos criar uma apli-cação completa na plataforma Android. Você ainda poderá conferir este projeto na íntegra, baixando o código-fonte do mesmo, no site da revista.
Essa aplicação é responsável por armazenar lis-tas de compras. Esse sistema é formado por três telas, conforme descrito abaixo.
Tela inicial: contendo todas as listas de
com-pras e os botões para Criar, Editar e Apagar uma lista, conforme mostrado na figura 5. Ao iniciar a tela, o sistema exibe todas as listas de compras cadastradas no banco de dados. Ao clicar em Criar, o sistema irá abrir a tela de edição de lista de compras, com uma nova lista. Clicando em Editar, o sistema irá carregar a tela de edição de lista de compras, com a lista sele-cionada, o botão “apagar” exclui a lista de compras do
banco de dados.
Tela de edição da lista de compras: contendo
o nome, lista de itens da compra, totalizador da com-pra e os botões de Adicionar, Editar e Excluir itens e Salvar e Cancelar as alterações da lista de compras. Conforme mostrado na figura 6. Ao clicar no botão adicionar o sistema abrirá a tela de edição de item da lista de compras, com um item novo. Clicando em Editar, o sistema irá carregar a tela de edição de item da lista de compras, com o item selecionado. O botão Excluir irá excluir o item em cache da lista. Só quando o usuário clicar em Salvar, a lista será incluída/alte-rada e seus respectivos itens serão todos excluídos do banco e adicionados novamente (isso facilita o pro-cesso, uma vez que teríamos que verificar item a item, se o mesmo, deve ser incluído, alterado ou excluído do banco de dados). Se o botão Cancelar for clicado, simplesmente o sistema ignora as alterações retor-nando a tela principal.
Tela de edição do item da lista de compras: Figura 4. Diagrama do padrão de projeto Observer.
<<interface>>
Observer <<interface>>Observable
+ notify() Observerlmpl1 Observerlmpl2 Observablelmpl + addObserver(Observer) + notifyObservers()
contendo nome, quantidade, valor unitário e valor total e os botões Salvar e Cancelar as alterações do item de compra. Conforme mostrado na figura 7, o
botão Salvar irá incluir o item no cache da lista e fará o sistema retornar a tela da Lista de Compras. Ao clicar em Cancelar o sistema ignora as alterações retornando a tela da Lista de Compras.
Veja o diagrama desse pequeno, mas funcional sistema na figura 8.
um detalhe peculiar de implementação do MVVM para a plataforma Android é a representação da camada View através de xmls. A View main_view. xml representa a tela inicial da aplicação, compra_ view.xml representa a tela de edição das Listas de Compras e item_compra_view.xml representa a tela de edição do Item da Lista de Compras.
Podemos observar que para cada View existe um respectivo ViewModel, isso ocorre porque cada tela possui um modelo específico de informações e ações. Já a camada Model, responsável por encapsu-lar o domínio do projeto, está representada por duas classes, CompraModel e ItemCompraModel.
Pré-requisitos
» Plugin do eclipse ADT
» SDK do Android com a versão 2.1
Preparação do ambiente
» Fazer checkout da última versão do projeto An-droid Binding, utilizando para isso uma ferra-menta cliente de SVN: http://android-binding. googlecode.com/svn.
» Criar um novo workspace.
» Importar o projeto AndroidBinding para o workspace.
Criando o projeto
» Clique no menu File, selecione New e clique em Other.
» Abra a aba Android e selecione Android Pro-ject. Clique no botão Next.
» Em Project Name, digite “ListaCompra”. Clique no botão Next.
Figura 7. Tela de edição do Item da Lista de Compras. Figura 6. Tela de edição da Lista de Compras.
MailViewModel CompraModel main_view.xml CompraViewModel ItemCompraModel compra_view.xml ItemCompraViewModel Item_compra_view.xml
» Selecione a versão do SDK a ser utilizada, no nosso caso a 2.1. Clique no botão Next.
» Em Package Name, digite “android.compra”. Clique no botão Finish.
» Após criar o projeto, acesse suas propriedades. Clique com o botão direito sobre o projeto e cli-que em Properties. Selecione a aba Android, na caixa Library clique em Add. Selecione o proje-to AndroidBinding e clique em ok.
Codificando
Ciclo de vida do Android Binding
O Android Binding tem seu próprio ciclo de vida e para o iniciarmos, devemos chamar o método init da classe Binder antes de começarmos a utilizar qual-quer recurso deste framework. Essa inicialização deve ser feita logo que a aplicação seja iniciada. Para isso devemos implementar o método onCreate da classe
Application (observe na Listagem 1 a classe que
es-tende Application).
Nativamente o android amarra as xMLs às clas-ses Activity, para que possamos prover um binding entre a camada View (xMLs) e a camada ViewModel, as classes Activity deverão estender BindingActivity herdando o método setAndBindRootView que deve ser chamado no evento onCreate preparando a fun-cionalidade para trabalhar no padrão MVVM (confor-me podemos ver nas Listagens 3, 4 e 5).
Na figura 9 podemos visualizar todo o ciclo de vida do Android Binding e na Listagem 2, como ficou o arquivo AndroidManifest.xml com a classe
Applica-tion e as classes Activity configuradas.
Listagem 1.
Inicializando o ciclo de vida do AndroidBinding.
publicclass MainApplication extends Application {
@Override
publicvoidonCreate() { super.onCreate(); Binder.init(this); }
}
Listagem 2.
AndroidManifest.xml configurado com asclasses Activity.
<?xmlversion=”1.0” encoding=”utf-8”?>
<manifestxmlns:android=”http://schemas.android.com/
apk/res/android” package=”android.compra” android:versionCode=”1” android:versionName=”1.0”> <uses-sdkandroid:minSdkVersion=”7”/> <application android:icon=”@drawable/ic_launcher” android:label=”@string/app_name” android:name=”MainApplication”> <activity android:name=”MainActivity” android:label=”@string/app_name” android:noHistory=”true”> <intent-filter> <actionandroid:name=” android.intent.action.MAIN”/> <categoryandroid:name= “android.intent.category.LAUNCHER”/> </intent-filter> </activity> <activity android:name=”CompraActivity” android:label=”@string/lista_compras”
android:noHistory=”true”></activity>
<activity
android:name=”ItemCompraActivity”
android:label=”@string/item_lista_compra”
android:noHistory=”true”></activity>
</application>
</manifest>
Figura 9. Diagrama do fluxo de uso do Android Binding. Activity <<framework>> Android Biding ViewModel Application View bind init
Listagem 3.
Classe MainActivity.publicclass MainActivity extends BindingActivity {
@Override
publicvoidonCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState);
this.setAndBindRootView(R.layout.main_view, newMainViewModel(this));
} }
Listagem 4
. Classe CompraActivity.publicclass CompraActivity extends BindingActivity {
@Override
publicvoidonCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState);
//…
this.setAndBindRootView(R.layout.compra_view, newCompraViewModel(this, model)); }
}
Listagem 5.
Classe ItemCompraActivity.publicclass ItemCompraActivity extends BindingActivity {
@Override
publicvoidonCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState);
//…
this.setAndBindRootView( R.layout.item_compra_view,
newItemCompraViewModel(this, model)); }
}
Criando os arquivos de layout (Views)
O próximo passo será criarmos as Views que são simplesmente layouts xML padrão do An-droid, com a adição do schema do Android Binding xmlns:binding=”http://www.gueei.com/android--binding/” que será responsável por marcar os ele-mentos visuais que serão amarrados com a ViewMo-del. Na Listagem 6 é exibido um dos arquivos, mais especificamente a tela de edição da lista de compras. Note que só são mostradas as principais proprieda-des do schema do Android Binding, “binding:text”, “binding:onClick”, “binding:itemSource” e “binding:itemTemplate”, no próximo tópico os mes-mos serão explicados com mais detalhes.
Listagem 6.
Tela de edição da lista de compras,arquivo compra_view.xml.
<?xmlversion=”1.0” encoding=”utf-8”?>
<LinearLayoutxmlns:android=”http://schemas.android.
com/
apk/res/android”
xmlns:binding=”http://www.gueei.com/ android-binding/” ...>
<TextView ... android:text=”Nome”/>
<EditText ... binding:text=”nome”>
<requestFocus/>
</EditText>
<TextView ... android:text=”Itens”/>
<ListView ...
binding:itemSource=”lista”
binding:itemTemplate=”@layout/lista_item_compra”
/>
<TextView ... binding:text=”total”/>
<LinearLayout ... android:orientation=”vertical”>
<LinearLayout ...>
<Button ... binding:onClick=”adicionar”/>
<Button ... binding:onClick=”editar”/>
<Button ... binding:onClick=”excluir”/>
</LinearLayout>
<LinearLayout ...>
<Button ... binding:onClick=”salvar”/>
<Button ... binding:onClick=”cancelar”/>
</LinearLayout>
</LinearLayout>
</LinearLayout>
Implementando os arquivos ViewModel
Agora devemos criar os respectivos modelos das views anteriores. Esses atuam através de classes nor-mais, pertencentes à camada VIewModel. Nas Lista-gens 7 e 8 podemos observar alguns dos principais recursos do Android Binding que irá nos auxiliar a implementarmos o padrão de projeto MVVM, iremos estudar cada um deles.
stringobservable: refere à propriedade
“binding:text” da View. Este recurso se trata de um observador (implementação do padrão de projeto Observer), cujo o papel é amarrar um valor String a um elemento do tipo EditText. A alteração do conte-údo de objetos desta classe é refletida na tela.
Dependentobservable: também referente à
que o mesmo é acionado caso o valor de um ou mais campos seja alterado. Muito utilizado em campos calculados, como é o caso do campo total, da tela de edição de item da lista de compra que é a multiplica-ção entre quantidade e valor unitário.
Arraylistobservable: refere à propriedade
“binding:itemSource” da View. Este recurso também se trata de um observador, cujo papel é amarrar uma lista ao elemento do tipo ListView. As alterações das informações presentes nos objetos desta lista são re-fletidas na tela.
command: são ações que no caso do nosso
exemplo são acionadas através das propriedades “binding:onClick”.
Arraylistitem: se trata de uma Inner Class
(se-guindo o padrão do ViewModel) criada para repre-sentar uma template do elemento visual ListView, referente à propriedade “binding:itemTemplate”. Es-tes templaEs-tes são arquivos do tipo layout xML que representam os elementos que serão exibidos em cada linha do elemento ListView. Na Listagem 9 note que este arquivo de template adota o mesmo padrão das Views exibidas anteriormente, somente com uma diferença, como representam uma linha, podemos ter propriedades como “binding:onClick” no elemento LinerLayout, acionando os comandos presentes na Classe ArrayListItem.
O Android Binding apresenta ainda mais recur-sos que não serão discutidos neste artigo. Exemplos completos de utilização destes recursos podem ser obtidos na documentação presente no site do projeto (veja link nas referências, no final do artigo).
Listagem 7.
Classe CompraViewModel.private CompraModel model;
private ArrayListItem itemSelecionado;
public StringObservable nome = newStringObservable();
public StringObservable total = newStringObservable();
publicfinal ArrayListObservable<ArrayListItem> lista = new ArrayListObservable<ArrayListItem>( ArrayListItem.class);
public Command adicionar = newCommand(){ publicvoidInvoke(View view, Object... args) { //…
} };
public Command editar = newCommand(){ publicvoidInvoke(View view, Object... args) { //…
} };
public Command excluir = newCommand(){ publicvoidInvoke(View view, Object... args) { //...
} };
public Command salvar = newCommand(){ publicvoidInvoke(View view, Object... args) { //…
} };
public Command cancelar = newCommand(){ publicvoidInvoke(View view, Object... args) { //…
} };
publicclass ArrayListItem {} }
Listagem 8.
Classe ItemCompraViewModel.publicclass ItemCompraViewModel {
private ItemCompraModel model;
public StringObservable nome = newStringObservable();
public StringObservable quantidade = newStringObservable();
public StringObservable valorUnitario = newStringObservable();
publicfinal DependentObservable<String> total = new DependentObservable<String>( String.class, quantidade, valorUnitario){ @Override
public String calculateValue(Object... arg0) throws Exception {
//…
} };
public Command salvar = newCommand(){ publicvoidInvoke(View view, Object... args) { //…
} };
public Command cancelar = newCommand(){ publicvoidInvoke(View view, Object... args) { voltarCompraView();
} }; }
Listagem 9.
Template da ListView da tela inicial do sistema.<?xmlversion=”1.0” encoding=”utf-8”?>
<LinearLayoutxmlns:android=”http://schemas.android.
com/apk/res/ android” xmlns:binding=”http://www.gueei.com/android-binding/” android:layout_width=”fill_parent” android:layout_height=”fill_parent” android:orientation=”horizontal” binding:onClick=”selecionar”> <TextView android:layout_width=”240dip” android:layout_height=”22dip” android:textSize=”20dip” android:gravity=”left” binding:text=”nome”/> <TextView android:layout_width=”80dip” android:layout_height=”22dip” android:textSize=”20dip” android:gravity=”right” binding:text=”total”/> </LinearLayout>
Implementando os arquivos Model
Por último, iremos implementar as classes refe-rentes à camada de domínio (Model). Na Listagem 10 é exibida uma das classes de domínio do sistema. Como o foco do artigo não é sobre acesso a banco de dados, não detalharemos a fundo estas classes, ficando somente a dica que estas, além de deterem o estado dos domínios, também são responsáveis por executar regras de negócios, presentes no nosso exemplo, em métodos como incluir, alterar e excluir.
Outro detalhe é que estas classes estendem Se-rializable, pois o Android serializa objetos comple-xos, ao serem passados como parâmetro de um Ac-tivity para outro. Veja um exemplo na Listagem 10.
Listagem 10.
Classe CompraModel.publicclass CompraModel implements Serializable {
private Long codigo; private String nome;
private List<ItemCompraModel> itens;
publicCompraModel() {
this.itens = new ArrayList<ItemCompraModel>(); }
// Métodos gets e sets
public Double getTotal() { Double total = 0.00;
for (ItemCompraModel item : itens) { total += item.getTotal();
}
return total; }
publicstatic List<CompraModel> obterTodas() {/* Acesso ao banco de dados */}
publicstatic CompraModel obterPorCodigo( Long codigo) {/* Acesso ao banco de dados */}
publicvoidincluir() {/* Acesso ao banco de dados */}
publicvoidalterar() {/* Acesso ao banco de dados */}
publicvoidexcluir() {/* Acesso ao banco de dados */}
}
Considerações finais
Foram apresentados os principais conceitos no desenvolvimento de aplicações utilizando-se o pa-drão de projeto MVVM, com a ajuda do framework Android Binding. Pudemos observar que esse padrão de projeto simplifica muito o desenvolvimento, sepa-rando as camadas e facilitando a criação de testes. Por se tratar de um projeto relativamente novo, o Android Binding tem uma pequena defasagem de documenta-ção a qual pode ser encontrada de forma simplificada em http://code.google.com/p/android-binding/wiki/, mas por ser tratar de um projeto open-source o mes-mo pode ser explorado com facilidade.
Site oficial do Android Binding: http://code.google.com/p/ android-binding/
Artigo original de John Gossman sobre MVVM: http://blogs.msdn.com/b/johngossman/ archive/2005/10/08/478683.aspx
Artigo original de Martin Fowler sobre Presentation Model: http://martinfowler.com/eaaDev/
PresentationModel.html