sábado, 21 de junho de 2008

XP - Extreme Programming

Aula 31


Extreme Programming (XP) é uma metodologia de desenvolvimento de software, nascida nos Estados Unidos ao final da década de 90. Vem fazendo sucesso em diversos países, por ajudar a criar sistemas de melhor qualidade, que são produzidos em menos tempo e de forma mais econômica que o habitual. Tais objetivos são alcançados através de um pequeno conjunto de valores, princípios e práticas, que diferem substancialmente da forma tradicional de se desenvolver software.


Esta metodologia prega que:

  • Indivíduos e interações entre eles são mais que processos e ferramentas;
  • Software em funcionamento é mais que documentação abrangente;
  • Colaboração com o cliente mais que negociação de contratos; ·
  • Responder a mudanças mais que seguir um plano.
Os valores da programação extrema se baseiam em:

Comunicação: Para que os desenvolvedores compreendam o que o cliente deseja e este último entenda os desafios técnicos que precisam ser vencidos, é preciso que haja comunicação entre as partes.

Coragem: Costuma-se dizer que a única constante em um projeto de software é a mudança. Clientes mudam de idéia com freqüência, mesmo quando fecham contratos nos quais, teoricamente, assumem o compromisso de não alterar o que está na especificação. Eles mudam porque aprendem durante o projeto e descobrem problemas mais prioritários a serem solucionados ou formas mais apropriadas de resolvê-los. Embora isso seja natural, gera uma preocupação para a equipe de desenvolvimento que, de tempos em tempos, precisa alterar partes do sistema que já estavam prontas, correndo o risco de se quebrar o que já vinha funcionando. È preciso coragem para enfrentar esses tipos de situações.

Feedback: Normalmente, quanto mais cedo descobrimos um problema, menos prejuízos ele pode causar e maiores são as chances de resolvê-lo de forma barata. Por isso, projetos XP estabelecem formas de encurtar ao máximo a defasagem de tempo entre o momento em que uma ação é executada e o seu resultado é observado. Assim, por exemplo, desenvolvedores procuram entregar novas funcionalidades no menor prazo possível, para que o cliente compreenda rapidamente as conseqüências daquilo que pediu. Os clientes, por sua vez, procuram se manter próximos dos desenvolvedores para prover informações precisas sobre qualquer dúvida que eles tenham ao longo do desenvolvimento.

Respeito: Respeito é um valor que dá sustentação a todos os demais. Membros de uma equipe só irão se preocupar em comunicar-se melhor, por exemplo, se se importarem uns com os outros. Respeito é o mais básico de todos os valores. Se ele não existir em um projeto, não há nada que possa salvá-lo. Saber ouvir, saber compreender e respeitar o ponto de vista do outro é essencial para que um projeto de software seja bem sucedido.

Simplicidade: O XP utiliza o conceito de simplicidade em inúmeros aspectos do projeto para assegurar que a equipe se concentre em fazer, primeiro, apenas aquilo que é claramente necessário e evite fazer o que poderia vir a ser necessário, mas ainda não se provou essencial.

Padrões GRASP - parte II (Variações Protegidas)

Aula 30


Como projetar objetos, subsistemas e sistemas de modo que as variações ou a instabilidade nesses elementos não tenha um impacto indesejável sobre outros elementos?
A VP é um princípio básico na motivação da maioria dos mecanismos e padrões na programação e no projeto para fornecer flexibilidade e proteção contra variações.
O encapsulamento de dados, das interfaces, e o polimorfismo são mecanismos básicos para se obter a VP. As técnicas de linguagens baseada em regras, interpretadores de regra, projetos reflexivos e de metadados, máquinas virtuais, etc, são mecanismos mais avançados para se obter a VP.


A seguir veremos alguns desses mecanismos e suas descrições de acordo o livro Utilizando UML e Padrões de Craig Larman:


Projeto dirigido por dados (data-driven designs): Os projetos dirigidos por dados englobam uma ampla família de técnicas que incluem códigos de leitura, valores, caminhos de arquivo de classe, nomes de classe, etc, de uma fonte externa para mudar o comportamento ou parametrizar um sistema de alguma maneiram, em tempo de execução.

Pesquisa de serviço: inclui técnicas como uso de serviços de atribuição de nomes ou negociantes para obter o serviço (o Jini do Java ou o UDDI para serviços web). Os clientes são protegidos contra variações na localização de serviços, usando a interface estável do serviço de pesquisa.

Projetos dirigidos pelo interpretador: os projetos dirigidos pelo interpretador incluem interpretadores de regra que executam regras lidas de uma fonte externa, interpretadores de script ou linguagem que lêem e executam programas, máquinas virtuais, mecanismos de rede neural que executam redes, mecanismos de lógica, etc. Esta estratégia permite mudar ou parametrizar o comportamento de um sistema por meio de expressões lógicas externas.

Projetos reflexivos ou de nível meta: O sistema é protegido contra o impacto de variações de lógica ou externas do código, por meio de algoritmos reflexivos que utilizam introspecção e serviços de metalinguagem.

Acesso uniforme: Algumas linguagens dão suporte a uma construção sintática de modo que os acessos a um método e a um campo de sejam expressos da mesma maneira.


Referências:


Larmam, Craig

Utilizando UML e Padrões: uma introdução à análise e ao projeto orientados a objetos e ao processo unificado - 2.ed - Porto Alegre:Bookmam, 2004.

Padrões GRASP - parte II (Invenção Pura e Indireção)

Aulas 28 e 29


Sabemos que os princípios de ouro para um bom projeto OO é o baixo acoplamento e a alta coesão, mas e se em algum caso a aplicação de um padrão violar um desses princípios?

Utilizaremos um exemplo dado no livro Utilizando UML e padrões de Craig Larman. No exemplo ele diz “Às vezes, os projetos orientados a objetos são caracterizados por implementarem como classes de software as representações dos conceitos do domínio do problema no mundo real para diminuir o hiato de representação (aqui ele usa o termo “hiato” para se referir às lacunas, espaço, o vago deixado quando se quer representar algo do mundo real no mundo virtual), por exemplo, uma classe Venda e uma classe Cliente.

Entretanto, existem muitas situações em que atribuir responsabilidades apenas às classes de software da camada do domínio leva a problemas em termos de coesão ou acoplamento inadequados ou a um baixo potencial de reutilização.

Suponha, por exemplo, que seja necessário suporte para salvar as instâncias de Venda em um banco de dados relacional. Segundo o padrão Especialista, atribuir responsabilidade à própria classe Venda seria justificável, pois venda tem os dados que precisam ser salvos. Entretanto, considere as implicações a seguir:

A tarefa exige um número relativamente grande de operações de suporte relacionadas ao banco de dados, nenhuma delas voltada ao conceito de venda, de modo que a classe Venda se torna não-coesa.
A classe Venda precisa estar acoplada à interface do banco de dados relacional, de modo que seu acoplamento aumenta.

Salvar objetos em um banco de dados relacional é uma tarefa muito geral, para a qual muitas classes precisam de suporte. Colocar essas responsabilidades na classe Venda sugere que vai haver uma reutilização inadequada ou muita duplicação em outras classes que fazem a mesma coisa.
Entenderam agora como a aplicação do padrão especialista levou a um alto acoplamento e uma baixa coesão? Mas nesse caso, o que fazer se não podemos deixar de aplicar o padrão especialista?

A resposta é o título desta postagem, o padrão Invenção Pura. Uma solução razoável para o problema acima é criar uma classe que seja responsável unicamente por salvar objetos em algum tipo de meio de armazenamento persistente, como um banco de dados relacional. Esta classe é uma Invenção Pura, uma criação da imaginação, e serve para tirar o acoplamento da classe Venda com o banco de dados.

Indireção

O objetivo deste padrão é muito parecido com o que estudamos acima, o padrão Invenção pura. Craig Larman cita em seu livro “Utilizando UML e padrões” que o objetivo do padrão indireção é “atribuir responsabilidade a um objeto intermediário para ser o mediador entre outros componentes ou serviços, para que eles não sejam diretamente acoplados. O intermediário cria uma indireção entre os outros componentes.

Geralmente, o padrão indireção e o Invenção Pura andam juntos, e o problema para o qual são a solução, geralmente é o mesmo, o alto acoplamento. Ao se aplicar um dos dois, não há a necessidade de aplicar o outro, a não ser que haja um certo choque de padrões, como foi explicado no exemplo anterior.

Padrões GRASP - parte II (Polimorfismo)

Aulas 26 e 27



Na área científica definimos polimorfismo como sendo uma propriedade que possui certas substâncias com a capacidade de se apresentarem sob muitas formas, sem mudarem de natureza, ou seja, de tipo. Em que esse pequeno parágrafo tem a ver com o design pattern polimorfismo? Segundo os autores do livro Core Java, Cornell & Horstmann, polimorfismo é a capacidade de um objeto decidir qual método aplicará a si mesmo, dependendo de onde se encontra na hierarquia de herança.

Complementando a idéia dos autores, podemos dizer em outras palavras que polimorfismo é a capacidade de um objeto de se transformar em outros objetos, dependendo do contexto onde está sendo aplicado, sem mudar o seu tipo, isso ocorre através dos métodos que são herdados de uma superclasse.

O questionamento que leva ao uso do polimorfismo é: como criar componentes de softwares conectáveis com base no tipo? Supomos que temos uma classe que faz três diferentes tipos de ações, imagine que uma outra classe sempre disparasse chamadas a essa classe, solicitando a execução de uma dessas ações, ou seja, quando chega a mensagem, teríamos sempre que testar qual seria o tipo de ação a ser executada, e só então executá-la.
If tipoação 1
...
Else
If tipoação 2
...
O design pattern polimorfimo prega que nunca teste o tipo de um objeto nem use condições lógicas no código para executar alternativas com base no tipo. Por que? Respondo com outra pergunta. E se o tipo mudar?
Com base no exemplo dado pelo Wikipedia vamos considerar a seguinte classe escrita em Java:

Esta é uma classe abstrata que representa qualquer operação matemática. Existem várias operações matemáticas, com isso não podemos ficar testando uma por uma. Note que, mesmo que a natureza do cálculo mude, a semântica do método calcular não muda, ou seja, ele sempre calculará o resultado da operação matemática que está sendo trabalhada.

Veremos duas subclasses que implementam duas dessas operações matemáticas

O seguinte trecho de código demonstra o uso do polimorfismo:

Embora o método calcular tenha sido chamado duas vezes em mostrarCalculo, o comportamento apresentado variou de acordo com a classe ao qual ele representava no momento.


http://www.mail-archive.com/java-list@soujava.org.br/msg09906.html
http://www.tecnoclasta.com/2007/12/18/aula-11-classes-interfaces-e-polimorfismo/
http://pt.wikipedia.org/wiki/Polimorfismohttp://www.dca.fee.unicamp.br/cursos/PooJava/polimorf/index.html

Padrões GOF (Padrão MVC

Aulas 24 e 25

MVC significa Model-View-Controller, traduzindo seria, Modelo-Vista-Controlador, para entendermos um pouco sobre um dos mais importantes padrões de projeto, vamos a um exemplo básico:
Imagine que você tenha um sistema de RH e três clientes:
· Um por comodidade só quer acessá-lo pela web;
· Outro por questão de segurança só quer acessar por desktop através de uma rede local;
· E um outro, mais moderno, só quer se conectar ao sistema através de um celular;


Haverá a necessidade de desenvolver 3 interfaces diferentes para cada usuário, um para cada tipo. Já as outras duas camadas, não necessariamente teriam que ser modificadas, tornando assim uma aplicação potencialmente reutilizável. A idéia principal do padrão MVC é isolar a aplicação em camadas distintas, basicamente, a camada de acesso a dados, a camada de apresentação, e a camada de negócios, que respectivamente são o Modelo, o Vista e o Controlador.

O modelo


O modelo é a parte do componente que encapsula os dados da aplicação. Na maioria das vezes vai fornecer rotinas para administrar e manipular dados. De modo geral, a técnica de acesso aos dados deve ser encapsulada no modelo. Desta forma, se uma aplicação for transferida de um sistema que usa um tipo de banco de dados para um sistema que usa outro, o único elemento que precisa ser alterado será o modelo - a vista e o controlador não precisam ser modificados.

A vista


A vista é a parte do componente usada para transformar e preparar os dados do modelo para que possam ser apresentados de alguma forma. O controlador retira os dados do modelo e os entrega para a vista. Esta, por sua vez, alimenta templates com estes dados para que possam ser apresentados ao usuário. A vista não modifica os dados de nenhuma forma, apenas os apresenta.

O controlador


O controlador é responsável pelas respostas às ações dos usuários. No caso de uma aplicação web, uma ação de usuário (geralmente) é a solicitação de uma página. O controlador vai determinar qual solicitação foi feita e vai responder de acordo fazendo com que o modelo manipule os dados necessários para depois passá-los para a vista para que possam ser mostrados.
Segundo o Wikipédia, um framework é uma estrutura de suporte definida em que um outro projeto de software pode ser organizado e desenvolvido. Pode incluir programas de suporte, bibliotecas de código, linguagens de script e outros softwares para ajudar a desenvolver e juntar diferentes componentes de um projeto de software.
Existem diversos frameworks que abrangem o padrão mvc, mas a maioria deles é voltada para aplicações web, a seguir serão apresentados alguns com os respectivos links direcionando para um material mais aprofundado sobre os mesmos, para quem deseja aprofundar.

ZEND FRAMEWORK
Zend Framework é um framework de código aberto que provê recursos para o desenvolvimento de aplicações e serviços WEB usando a linguagem de programação PHP. Propõe-se a oferecer uma biblioteca de recursos de grande poder, fornecendo soluções modernas, robustas e seguras para o desenvolvedor. Inclui, também, diversos componentes de integração com APIs de serviços, como Flickr, Amazon e Delicious, entre outros.
TUTORIAL SOBRE O ZEND FRAMEWORK
http://akrabat.com/wp-content/uploads/iniciando-com-zend-framework_130.pdf

WEBWORK
O WebWork é um framework java que trabalha com MVC de nível 2. Ele desenvolve o papel de controlar, isto é, ele é o responsável por fazer o direcionamento de acordo com cada requisição. Nele está configurado qual ação (Action) deve ser chamada em cada caso.
FÓRUM SOBRE O WEBWORK CONTENDO UM PEQUENO TUTORIAL
http://www.javafree.org/javabb/viewtopic.jbb?t=8798

ASP.NET MVC FRAMEWORK
Framework da microsoft baseado no padrão MVC para linguagem asp.net. É necessário utilizar o visual studio, ferramenta também da microsoft para desenvolvimento de software.
TUTORIAL SOBRE O ASP.NET MVC FRAMEWORK
http://msdn.microsoft.com/pt-br/magazine/cc337884.aspx


JAVA SERVER FACES
O Java Server Faces é um framework MVC para o desenvolvimento de aplicações Web, que permite o desenvolvimento de aplicações para a internet tal como fazíamos com Delphi ou Visual Basic, ou seja, arrastanto e soltando os componentes na tela (JSP), definindo propriedades dos mesmos.
TUTORIAL SOBRE O JAVA SERVER FACES
http://www.guj.com.br/content/articles/jsf/jsf.pdf


REFERÊNCIAS
http://pt.wikipedia.org/wiki/Apache_Struts
http://www.linhadecodigo.com.br/Artigo.aspx?id=1602
http://www.javafree.org/javabb/viewtopic.jbb?t=8798
http://www.javafree.org/wiki/WebWork
http://akrabat.com/wp-content/uploads/iniciando-com-zend-framework_130.pdf
http://pt.wikipedia.org/wiki/Zend_Framework
http://www.javafree.org/javabb/viewtopic.jbb?t=853237
http://msdn.microsoft.com/pt-br/magazine/cc337884.aspx
https://saloon.inf.ufrgs.br/twiki-data/Disciplinas/CMP167/TF07RuthianoMunaretti/SlidesWebWork.pdf
http://www.marcelomx.com/2007/04/26/desenvolvendo-no-padrao-mvc-com-zend-framework/
http://www.numaboa.com/informatica/tutos/joomla/885-mvc
http://www.guj.com.br/content/articles/jsf/jsf.pdf
http://www.javafree.org/javabb/viewtopic.jbb?t=11749

Padrões GOF (Padrão Command)

Aulas 22 e 23

O objetivo do padrão command é encapsular uma requisição como um objeto permitindo que os clientes parametrizem diferentes requisições, filas ou fazer o registro de log de requisições e dar suporte operações que podem ser desfeitas.
Pra quem não está familiarizado com a maioria dos termos utilizados em java, ou nas linguagens orientada a objeto, vamos procurar entender da maneira mais simples. Encapsulamento para muitos se resume aos métodos get e set, que dá a idéia de proteger um objeto para que ele não seja acessado por qualquer um.
Mas a idéia transmitida pelo padrão command nada tem a ver com encapsulamento como proteção aos dados, mas sim com uma maneira de parametrizar as solicitações dos objetos de forma que estes não fiquem acoplados.
Um exemplo real do uso do padrão command pode ser visto na implementação de uma aplicação cliente/servidor onde geralmente temos o componente Menu que é composto de vários itens. Cada item do menu eqüivale uma operação, como salvar um arquivo, ler arquivo, apagar arquivo, selecionar a paleta de cores e etc.. Quando selecionamos um item do menu uma operação deve ser realizada. Esta operação pode ser encapsulada em um objeto, assim reduziremos o acoplamento entre o objeto menu e o objeto que executa a operação.
Quatro são os participantes na implementação do padrão command:
· Command: Classe abstrata ou interface para execuçãode uma operação.Deve implementar o método abstrato chamado execute.
· CommandAction: Classe concreta que implementa o método execute, ela deve ser uma subclasse se Command for uma classe abstrata, se Command for uma interface então ela deve realizar essa interface.
· Invoker: Objeto que faz uma requisição ao Command para que execute uma operação.
· Receiver: Objeto responsável por executar uma operação.
Abaixo seguem os diagramas de classe e de seqüência que explicam mais detalhadamente essa seqüência de mensagens.

Em tempo de execução o objeto Invoker chama o método execute() do objeto Command que delega ao método action() do objeto receiver que executará a operação.



Link: http://tramos.railsplayground.net/assets/2008/5/17/Padrao_20Projeto_20Command.pdf
http://pt.wikipedia.org/wiki/Command
http://www.dsc.ufcg.edu.br/~jacques/cursos/map/html/pat/command.htm


segunda-feira, 12 de maio de 2008

Padrões GOF (Padrão Oberver)

Aulas 20 e 21

Em um sistema orientado a objeto, o foco principal é a comunicação entre os objetos, e os padrões que já estudamos anteriormente tratam bem dessa questão, e não é diferente com o que vamos ver a seguir.

Geralmente, um objeto coleta informação de outro chamando seu método, no entanto, quando um objeto muda, os objetos clientes não têm como saber se aquele objeto mudou e assim o cliente pode deixar de utilizá-lo. O padrão Observer permite que objetos interessados (clientes), sejam avisados da mudança de estado ou evento ocorrendo em outro objeto. A intenção é definir uma dependência um-para-muitos, assim, quando um objeto mudar de estado, todos os seus dependentes sejam notificados e atualizados automaticamente.

Em java.swing o objeto que está sendo observado (aquele que pode mudar) é chamado de “Source”, e o objeto que observa (o objeto que está interessado, o cliente), é chamado de “Listener”.

Existem muitas controvérsias quanto ao uso deste padrão, principalmente entre as soluções dadas pelo GOF, baseada em java swing e as soluções apresentadas por autores que seguem a implementação em java, em especial Bill Venners, portanto, vale analisarmos as soluções da cada um para entendermos, no link a seguir, encontra-se um exemplo que segue o paradigma de Bill Venners, e no diagrama uml encontra-se as definições do GOF, onde o observer é o objeto que observa, e subject, aquele que é observado.

Em Java, um objeto (o Source/Subject ) envia informação para outro objeto (o Listener/Observer) pela chamada de um método do Listener/Observer. Mas, para que isso seja possível:

    • O Source/Subject deve ter uma referência ao Listener/Observer.
    • O tipo desta referência deve ser uma classe ou interface que declare ou herde o método a chamar

Fazer com que o tipo da referência seja a classe (concreta) do Listener/Observer não funciona bem, porque:

    • O número e tipos dos Listeners/Observer não é conhecido em tempo de compilação
    • Os vários listeners/Observers poderão não fazer parte de uma mesma hierarquia de objetos
    • Não queremos criar um acoplamento forte entre Source/Subject e Listeners/Observers.

A solução vai se basear primordialmente em interfaces para resolver o problema

    • Aliás, este é um excelente exemplo do poder de interfaces para prover polimorfismo envolvendo classes não relacionadas por herança (de implementação)

A seguir temos um diagrama UML que demonstra a utilização de interfaces para servir como referência ao Source/Subject, ao invés da sua classe concreta.

REFERÊNCIAS


UFCG, Artigo, Padrão Observer segundo Bill Venners

quarta-feira, 30 de abril de 2008

Padrões GOF (Padrão Singleton)

Aulas 18 e 19

Quando falamos em java, vem logo a idéia de objetos que são criados a partir de instâncias de classes e de reutilizar essas classes para que sejam criados outros objetos quando não mais for necessários aqueles que estas classes criavam. Pois bem, podemos criar vários objetos a partir de instâncias de uma mesma classe, mas o que vamos ver nesse padrão, é totalmente ao contrário, ou seja, o padrão singleton, sugere que apenas uma instância da classe seja criada e garante que mais ninguém crie outra instância, mas em que casos precisaremos usar apenas uma instância de uma classe? Como disse Metsker em seu livro Padrões de Projeto em java, “é mais fácil explicar como garantir que uma classe só tenha uma instância do que explicar por que nós podemos desejar essa restrição”, mas vamos tentar dar um exemplo para que não fique muito vaga essa idéia do singleton. Em uma aplicação que necessite de um log de dados (termo utilizado para descrever o processo de registro de eventos relevantes num sistema computacional), pode-se implementar uma classe com o padrão singleton, desta forma existe apenas um objeto responsável pelo log em toda a aplicação que é acessível unicamente através da classe singleton.

Segundo Metsker, dispomos de várias maneiras para criar um singleton, todavia, o importante é garantir que outros desenvolvedores não criem novas instâncias da classe que queremos limitar, portanto, vamos à solução:

É de conhecimento comum que, para criar uma instância de uma classe, devemos chamar o seu construtor, normalmente, esses construtores são públicos, muitos desenvolvedores desconhecem, mas é possível criar um construtor privado, assim, a classe só pode ser instanciada dentro de algum dos seus próprios métodos.

Criada a classe com o método privado, agora temos que criar uma variável que armazene a instância dessa classe.

Talvez você esteja se perguntando porque utilizar variável estática, simplesmente porque uma variável estática não perde o seu valor cada vez que ela for instanciada, assim, se a classe singleton for instanciada, o valor da instância permanecerá na variável e quando alguém tentar instanciá-la novamente, um método implementado para essa finalidade retornará aquele valor que já havia nela quando foi instanciada pela primeira vez (essa é a funcionalidade principal de um singleton).

Assim, com o código acima, ao instanciarmos os objetos m1 e m2, será retornado o mesmo valor para os dois.

Mas ainda há um pequeno problema quanto a esse código. Em ambientes multi-threaded, pode ocorrer de duas threads tentarem instanciar o objeto ao mesmo tempo, nesse caso, haverá um problema, provavelmente as duas conseguirão instanciar e serão criados dois objetos, o que fere a mecânica do singleton, uma solução para este problema seria utilizar o atributo syncronized no método getInstance(), este atributo garante a sincronização das threads que tentam instanciar a classe singleton, em outras palavras, garante que outra thread não possa acessar a classe até que a thread que a acessou pela primeira vez tenha terminado de fazê-lo.

O singleton é um dos padrões que não devem ser utilizados frequentemente, pois o uso abusivo de singletons leva a soluções onde a dependência entre objetos é muito forte, além do que, uma situação em que realmente é necessária apenas uma instância de uma classe é difícil.


REFERÊNCIAS


WMagician, Artigo, Padrão Singleton em Java

Macoratti, José Carlos Macoratti, Artigo, O Padrão Singleton

Manual do PHP, Escopo de variáveis

Metsker, Steven John Metsker, Padrões de Projeto em Java

segunda-feira, 21 de abril de 2008

Padrões GOF (Padrão Adapter)

Aula 17

Como vamos utilizar a classificação de Metsker para nossos estudos sobre os padrões GOF, nesta postagem apresentaremos o padrão Adapter.

O principal objetivo do Adapter é facilitar a conversão da interface de uma classe para outra interface mais interessante para o cliente, fazendo com que várias classes possam trabalhar em conjunto independentemente das interfaces originais. O Adapter é utilizado quando uma classe já existente e sua interface não combinam com a esperada pelo cliente ou se deseja-se criar uma classe reutilizável que coopera com classes não relacionadas ou não previstas, ou seja, classes q não necessariamente tenham interfaces compatíveis, entre outras utilizações.

O padrão Adapter tem finalidade estrutural e abrange tanto escopo de classe quanto de objeto, por isso existe o adaptador de classe e o adaptador de objetos, o primeiro é utilizado quando o alvo é uma interface, consequentemente usa herança múltipla, o segundo é utilizado quando o alvo é uma classe e faz uso da agregação.

Imagine que utilizamos uma classe utilitária de um framework especializado em métodos para programadores iniciantes, nesta classe existe um método que será depreciado no futuro (sem utilização), ou seja, digamos que novas versões da classe sejam lançadas e o método tenha sido retirado definitivamente, como poderemos utilizar a nova versão da classe em nossa aplicação que utiliza a versão antiga do método? Se apenas substituirmos a classe, será disparado um erro afirmando que está sendo feita uma chamada que não existe.

È aí que entra o padrão adapter, com duas formas para resolver esse problema:

1. Criamos uma classe intermediária que servirá como interface entre as chamadas de código cliente e o código da classe, essa nova classe trabalhará basicamente como um filtro entre essas chamadas, o que caracteriza um adaptador de objetos, utilizando agregação.

2. Criamos uma classe que herdará da antiga e sobrescrevemos ou recriamos o método chamado, caracterizando dessa forma um adaptador de classes, utilizando herança.

A escolha da forma de implementação do adapter é uma decisão do arquiteto de software e dependerá do contexto da aplicação.Utilizaremos aqui a 1ª opção.

Vamos ao exemplo prático:

Imagine que você esteja aprendendo java e já sabe alguns padrões de projeto, então você é um programador iniciante, teremos então a classe INICIANTE.

Esta classe utiliza dois métodos, SlaverJava() que representa apenas os conhecimentos que você tem sobre java e Padrões() que representa os conhecimentos que você tem sobre Padrões.

Suponhamos que daqui um tempo você adquira mais conhecimentos em java, então o método SlaverJava() não terá utilização, além da necessidade de implementar um novo método na classe. Como mencionado anteriormente, se apenas substituirmos a classe, será disparado um erro ao ser feita qualquer chamada para os métodos dessa classe.

A solução seria criar uma nova classe adaptadora contendo uma chamada para uma outra classe que contém o novo método, servindo como interface entre as chamadas de código cliente para os métodos da classe Iniciante, implementando essas chamadas na nova classe.

Criamos então uma nova classe chamada programadorMédio, que seria a nova versão da classe Iniciante, se essa classe apenas herdasse da classe iniciante e reescrevesse esse novos métodos, não seria caracterizado a utilização do padrão adapter e sim uma simples herança. Sendo assim, vamos implementar a classe programadorMedio como uma interface contendo apenas o novo método que irá substituir o SlaverJava.

Criamos então a classe adaptadora, chamada IntermediarioAdapter que herda da classe Iniciante, reescreve o novo método e implementa na classe programadorMedio.


Com isso finalizamos o padrão adapter, um exemplo bem simples mas que explica bem o conceito principal deste padrão.



Download do aplicativo no Netbeans


REFERÊNCIAS

CEFET-PARANÁ, Padrões de Projeto, ARTIGO

Èrico Almeida, IMASTERS fórum, Padrões de Projeto-Adapter

Steven John Metsker, Design Patterns Java Workbook.Addison-Wesley, 2002

Introdução a Padrões GOF

Aula 16

Nos artigos anteriores vimos alguns dos padrões GRASP, suas finalidades, alguns exemplos de aplicação e com isso, conhecemos a importância desses padrões para um projeto de software de qualidade.

Nas próximas postagens, veremos alguns dos padrões GOF, mas antes, um breve resumo dos criadores dos padrões GRASP e GOF:

Como já sabemos, o conceito de padrões foi criado pelo arquiteto Christopher Alexander (Christopher Alexander. A Pattern Language. Estados Unidos da América: Oxford University Press, 1977), a partir dos conceitos criados por Alexander, os programadores Kent Beck e Ward Cunningham, propuseram os primeiros padrões para a área de ciência da computação, mas foi com o lançamento do livro Design Patterns, Elements of Reusable Object-Oriented Sofware, cujos autores são Erich Gamma, Richard Helm, Ralph Johnson e John Vlissides, conhecidos como a "Gangue dos Quatro" (Gang of Four ou GOF), que o movimento ao redor de padrões de projeto ganhou popularidade. Posteriormente, vários outros livros do estilo foram publicados, como Applying UML and Patterns: An Introduction to Object-Oriented Analysis and Design and Iterative Development, que introduziu um conjunto de padrões conhecidos como GRASP (General Responsibility Assignment Software Patterns).

Nos artigos publicados, conhecemos os padrões GRASP, mas como visto no parágrafo anterior, o primeiro conjunto de padrões a surgir foram os padrões GOF. Existem várias formas de classificar os padrões GOF, por exemplo, em GAMMA(2000), são apresentados 23 padrões classificados em 3 categorias: Criacional, Estrutural e Comportamental, já em METSKER(2004), são apresentados diversos padrões, os quais são classificados em Interfaces, Responsabilidades, Construções, Operações e Extensões.

Abaixo temos uma ilustração dessas classificações:


Não entraremos em detalhes sobre todos esses padrões, mas ao longo das próximas postagens, veremos os mais importantes, bem como suas caracterizações e aplicações. Por hora vamos descrever alguns dos problemas mais comuns em um projeto OO, e como esses padrões podem ajudar a resolvê-los.

Problema I: Como descobrir e quais os objetos mais apropriados?
Design patterns ajudam a identificar as abstrações menos óbvias e objetos que podem representá-las.

Problema II: Qual a granularidade ideal para um sistema?
Design patterns oferecem várias soluções como por exemplo: Façade descreve como representar subsistemas inteiros como um único objeto, Flyweight descreve como suportar grandes quantidades de objetos nas menores granularidades, Abstract Factory, Builder, Visitor e Command limitam a responsabilidade de objetos.

Problema III:Como especificar interfaces?
Design patterns ajudam a definir interfaces ao identificar seus elementos-chave e tipos de dados que são passados
.

Problema IV: Como especificar implementações?
Design patterns oferecem formas de instanciar classes concretas em outras partes do sistema.

Problema V: Como fazer o reuso funcionar?
Design patterns usam delegação para tornar a composição tão poderosa para reuso quando a herança.

Problema VI: como distinguir estruturas estáticas (compile-time) e dinâmicas (run-time)?
Vários design patterns capturam a distinção entre estruturas run-time e compile-time.

Problema VII: como antecipar mudanças?
Padrões promovem desacoplamento e permitem que algum aspecto da estrutura do sistema varie independentemente de outros aspectos.

Em meio a uma certa quantidade de padrões, os mais inexperientes podem ficar um pouco perdidos na hora de escolher qual padrão utilizar em determinada situação, aqui vai algumas dicas de como selecionar esses padrões.

1. Considere como os padrões solucionam os problemas de projeto

2. Analise seu problema e compare com o objetivo de cada padrão

3. Veja como os padrões envolvidos se relacionam entre si

4. Estude padrões de propósito ou intenção similar (veja formas de classificação)

5. Examine causas comuns que podem forçar o redesign do seu sistema

6. Considere o que deve variar no seu design




REFERÊNCIAS:


UNIVERSIDADE TECNOLÓGICA DO PARANÁ, Introdução a Padrões de Projeto


RICARDO ISHIBASHI MOREIRA DE ALMEIDA, Utilização de padrões de projeto no desevolvimento de aplicações web com PHP 5


WIKIPÉDIA, Padrões de projeto de software

terça-feira, 1 de abril de 2008

Padrão controlador

aula 15 (breve resumo, sujeito a modificações)


Um evento de entrada de um sistema é um evento gerado por um ator externo. Ele está associado com operações do sistema, operações do sistema em resposta a eventos do sistema, da mesma forma que os métodos e as mensagens estão relacionados. O padrão responsável por tratar os eventos do sistema é chamado de padrão controlador.

Por exemplo, qualquer usuário de um sistema que pressione algum botão, como por exemplo o botão fechar de algum programa, ele está disparando um evento do sistema que indica que o programa está sendo encerrado.

A primeira categoria de controlador é um controlador fachada (facade) que representa todo o sistema, o dispositivo ou o subsistema. A idéia é escolher uma classe cujo nome sugira uma cobertura, ou fachada, sobre as outras camadas da aplicação e que seja o ponto principal para as chamadas provenientes de interface com usuário para as camadas abaixo. Os controladores fachada são adequados quando não existem muitos eventos de sistema, ou quando não é possível, para a interface de usuário, redirecionar mensagens de eventos de sistema para controladores alternativos.

Quando o controlador fachada começa a levar o projeto a ficar com baixa coesão e alto acoplamento, o que ocorre quando o controlador começa a ficar “inchado”, com excesso de responsabilidades, é ideal utilizar um controlador para cada caso de uso do sistema. Um controlador de caso de uso é uma boa escolha quando existem muitos eventos de sistema com diferentes processos, ele fatora o seu tratamento em classes separadas administráveis e também fornece uma base para conhecer o estado do cenário do processo em andamento.

Padrão Alta Coesão

Aula 14


Veremos agora um padrão que muito se parece com o estudado anteriormente, com a diferença que este mede o quão estão relacionadas as responsabilidades de uma classe enquanto que o outro foca a medida do quanto um elemento está conectado, tem conhecimento ou depende de outros elementos. O resultado é praticamente o mesmo, tanto que ao se aplicar um deles, consequentemente estará aplicando o outro, são raros os casos em que isso não acontece.

Ao estudarmos o padrão baixa coesão, surge um pouco dos conceitos que também já estudamos nas primeiras postagens, por exemplo:

Uma classe com baixa coesão faz muitas coisas não relacionadas ou executa muitas tarefas. Uma classe que executa muitas tarefas não possui a aplicação do padrão especialista, pois, não há delegação de responsabilidades, bem como tarefas que não são adequadas a ela. Classes com múltiplas responsabilidades ou com alta granularidade estão propensas a ter uma alta coesão.

Assim como o baixo acoplamento, a alta coesão é um dos princípios que devem ser levados em consideração ao se construir um projeto.

Da mesma maneira que o baixo acoplamento, a alta coesão também é dividida em tipos:

Ø Coesão coincidental: o pior tipo de coesão, há nenhuma ou pouca relação construtiva entre os elementos de um módulo, em outras palavras é uma classe inchada, com um punhado de métodos, todos executando tarefas diferentes, sem nenhuma relação com a classe que os implementa.

Ø Coesão lógica: melhor do que a coincidental mas não menos pior em um projeto, semelhante ao acoplamento de controle, onde um módulo faz um conjunto de funções relacionadas e uma das quais é escolhida através de um parâmetro para controlá-lo.

Ø Coesão temporal: os elementos estão agrupados no mesmo módulo simplesmente porque são processados no mesmo intervalo de tempo, semelhante aos arquivos .ini do windows xp, ao iniciar o xp esses arquivos são carregados para iniciar serviços ou aplicativos.

Ø Coesão procedural: o módulo só tem sentido sobre a aplicação associada, sem ela, há dificuldade em entendê-lo, basicamente é a coesão relacionada aos procedimentos executados pelos elementos do módulo.

Ø Coesão de comunicação: um módulo tem coesão de comunicação se os seus elementos usam a mesma entrada ou a mesma saída.

Ø Coesão seqüencial: a saída de um elemento é a entrada de outro e a solução é decompor em módulos menores, isso nós já vimos em tópicos passados, chamado também de acoplamento de dados.

Ø Coesão funcional: Um módulo funcionalmente coeso contém todos os elementos e apenas aqueles necessários para realizar uma única tarefa bem definida.

o Exemplos:
- calcular raiz quadrada;
- ler registo;
- determinar salário líquido de um empregado;
- calcular o ponto de impacto de um míssil.

Um módulo não será funcionalmente coeso se, para descrever sua função for necessário um, ou mais, dos seguintes items:


- Frase composta;
- Mais do que uma frase;
- Palavras que indiciam uma ligação temporal;
- Falta de um objectivo específico simples;
- Verbo ambíguo.

segunda-feira, 24 de março de 2008

Padrão Baixo Acoplamento

Aulas 12 e 13


Acoplamento de Controle

Anteriormente discutimos o acoplamento de dados, o menos pior dos acoplamentos, foi explicado que a melhor solução para diminuir este tipo de acoplamento é o uso de interface, aliás, para diminuição de todos os tipos de acoplamento o melhor caminho é o uso de interface. No acoplamento de dados, como o próprio nome já diz é aquele em que um objeto conhece muito os dados de outro, no próximo tipo que iremos discutir, chamado acoplamento de controle, não existe este conhecimento, mas sim, um certo controle de um certo objeto sobre o outro, explicando melhor:

Objeto A manda uma mensagem a objeto B;

Objeto B usa um parâmetro da mensagem para decidir o que fazer;


Exemplo:

Considere a classe Circuito como objeto A e classe Lâmpada como o objeto B:

O objeto circuito instancia a classe lâmpada, e passa os parâmetros desligada, ligada e piscando, a classe lâmpada então atribui um valor a cada parâmetro e executa a o procedimento para conhecer o estado da lâmpada.

Problema: em termos mais diretos, quem comanda o interruptor? Claro que a classe circuito, mas qual o problema nisso? Afinal, alguém tem que fazer isso. O problema não é alguém fazer, mas a forma como é feito, se ao invés da classe circuito mandar uma mensagem passando um parâmetro para desligar a lâmpada, somente passasse uma mensagem para desligá-la e a classe responsável executasse o procedimento, da maneira que lhe fosse convincente, seria muito mais prudente, afinal as duas não precisariam andar sempre de mãos dadas, característica do alto acoplamento.

Como no exemplo acima, a classe circuito cria um novo objeto de lâmpada e ao invés de passar parâmetros, cria métodos para passar mensagens.

A classe lâmpada, anteriormente não tinha métodos, apenas as comparações de if e else, mas utilizando um princípio para diminuir o acoplamento em casos de acoplamento de controle, decompomos a operação em múltiplas operações, ou seja, o método “public void setLampada(int valor)” do primeiro exemplo de lâmpada, em diversos métodos, como visto no segundo exemplo.


Acoplamento de Dados Globais

O terceiro tipo de acoplamento é o de dados globais, este tipo de acoplamento ocorre da seguinte maneira:

Dois ou mais objetos compartilham estruturas de dados globais, estes tipos de dados podem ser enxergados por todas as classes do sistema, pois como o próprio nome já diz é global.

Uma chamada de método pode mudar um valor global e o código não deixa isso aparente.


Acoplamento de Dados Internos

O quarto e último tipo de acoplamento, e o pior de todos é o acoplamento de dados internos, ocorre quando um objeto consegue alterar os dados locais de outro objeto, exemplo, uma variável de classe pública ou protected em java.

Solução: sempre utilizar encapsulamento, ou seja, variáveis private e métodos get e set.

sexta-feira, 21 de março de 2008

Padrão Baixo Acoplamento

Aula 11


Acoplamento de Dados

Acoplamento de dados, como já vimos, é o tipo de acoplamento onde uma classe conhece os dados da outra, fazendo com que se houver mudança em uma, automaticamente implicará mudança em outra.

Observe o exemplo a seguir, de uma classe aluno e uma classe lista ordenada, a finalidade delas é obter a matrícula de um aluno e coloca-las em uma lista ordenada.

A classe aluno obtêm a matrícula e o nome do aluno através do método get, bem como cria um novo objeto novoAluno e adiciona a lista de alunos, chamando assim a classe lista ordenada. Observe agora a classe lista ordenada:

A classe lista ordenada recebe um objeto do tipo aluno, e agora já observamos um problema de acoplamento, a classe lista ordenada nunca poderá receber um objeto de outro tipo para que seja comparado. Continuando, através do método add, a classe compara os objetos através da variável matrícula, que só existe na classe aluno, e aí observamos mais um acoplamento, e se a variável matrícula deixar de existir na classe aluno? E se for necessário comparar os alunos não por matrícula mas por ordem alfabética?.

Para isso, vamos refatorá-las para que as duas não mais dependam uma da outra.

Uma das melhores soluções para reduzir o acoplamento é a utilização de interface, vamos relembrar o que vem a ser uma interface. Uma interface nada mais é que uma superclasse que adiciona funcionalidades à classe que a implementa, ou seja, se uma determinada classe implementa uma interface, é como se ela assinasse um contrato e em troca receberia a garantia de que iria implementar as funcionalidades que existem na interface.

Observe como ficou a classe aluno:

Qual a primeira mudança que notamos? Isso mesmo, a classe Aluno agora está implementando uma interface chamada “comparable”, que é a interface que permite fazer comparação de objetos. Em seguida encapsula as variáveis com os métodos get e set, o que também não acontecia no exemplo anterior, em seguida há o método compareTo, um método da interface comparable, esse método transforma aluno em uma variável do tipo comparable (Aluno aluno = (Aluno)o), e em seguida faz a comparação para retornar um inteiro à classe que irá fazer a ordenação, nesse caso a classe ListaOrdenada.

A classe ListaOrdenada instancia a lista, recebe o novo elemento, põe na ordem correta e o insere na lista.

Agora qual a diferença principal que notamos nessas duas classes? A classe listaordenada é capaz de ordenar qualquer tipo de objeto, e não somente a matrícula, como era no exemplo anterior, se houver uma mudança na classe aluno, a classe listaordenada continuará ordenando pois o objeto que é passado a ela não é um objeto do tipo aluno e sim do tipo comparable.

quinta-feira, 20 de março de 2008

Padrão Baixo Acoplamento

Aula 10


Em um sistema orientado a objetos, os objetos são todos interligados, uns mandando mensagens a outros, como já vimos até agora, existem aqueles que têm a responsabilidade de conhecer qual o responsável por determinada ação, ou quem possui determinada informação para executar tal ação, e existem aqueles com a responsabilidade de fazer as ações, de executa-las.

O padrão que vamos conhecer hoje é responsável por medir o quanto uma classe está ligada a outra, isso é possível através do diagrama de classe, quando se observa a ligação fisicamente, ou quando avaliamos uma classe e constatamos que ela tem muito conhecimento de outra, ou quando uma classe depende de muitos elementos de outra classe, isso se chama alto acoplamento.

O alto acoplamento traz diversos problemas para um sistema, entre eles:

1. Difícil entendimento: vamos imaginar uma situação em que você precisa fazer uma reengenharia de um sistema que já está pronto, ou que necessita encontrar um erro que está lhe dando dor de cabeça no seu sistema, ao começar analisar as classes descobre que para entender essa classe, precisa estudar a próxima que está ligada a ela, para também entender esta, precisa estudar a próxima, e assim por diante, imagine o tempo que irá desperdiçar nisso.

2. Difícil reutilização: vamos imaginar outra situação, digamos que seja necessário retirar uma determinada parte do sistema, algo como um módulo de calcular folha de pagamento de um sistema financeiro, para ser levada e adequada a outro sistema financeiro, imagine que as classes responsáveis por isso, estejam ligadas ao módulo de RH, você vai levar o módulo de RH junto?

3. Propagação de mudanças: continuando do item anterior, imagine que seja necessário mudar uma classe do módulo de folha de pagamento, para isso, teria que mudar a classe que está no módulo de RH, e se você não for o responsável pelo módulo de RH? E se além de ter que mudar esta classe, também mudar várias outras que estão ligadas à primeira.

A solução para isso seria minimizar o acoplamento entre as classes, ou seja, deixa-las com baixo acoplamento.

Existem quatro tipos de acoplamento:

  • Acoplamento de dados: quando uma classe conhece os dados da outra;
  • Acoplamento de controle: quando uma classe exerce controle sobre o comportamento de outra.
  • Acoplamento de dados globais: quando dois ou mais objetos compartilham os mesmos dados.
  • Acoplamento de dados Internos: quando um objeto altera os dados locais de outro objeto, isso em java não é difícil de evitar, é só utilizar variáveis private, ao invés de públicas.

O acoplamento fraco é um princípio a ser levado em conta em todas as decisões de projeto, pois é um princípio de avaliação que o projetista aplica enquanto avalia as decisões do projeto.

quinta-feira, 13 de março de 2008

Padrão Criador ( na prática )

Aula 9 (Laboratório)


Sabemos que a criação de objetos é uma das atividades mais comuns em um sistema orientado a objeto, e é útil ter um princípio para atribuição geral de responsabilidades de criação. Seguindo estes princípios o sistema apresentará maior clareza, acoplamento fraco, encapsulamento e reutilização, nos artigos anteriores discutimos todas essas qualidades, e portanto não há necessidade de defini-las novamente.

Veremos agora uma aplicação prática do padrão criador, utilizando os mesmos diagramas e praticamente o mesmo código da AULA 8, mas um pouco mais completo.

Pelo texto da postagem anterior, sabemos que a classe “Venda” é responsável por calcular o total de uma venda, a classe “ItemVenda” por calcular o subtotal e a classe “Produto” por saber o preço unitário de cada produto, agora a questão é: quem é responsável por criar quem? Qual dessas classes cria a instância de outra? Pelo primeiro diagrama, percebe-se que a classe “produto” não cria ninguém, ela é apenas criada, então vamos começar por ela.

Uma vez que a classe produto só possui métodos acessores e mutatórios, ela não precisa ser instanciada mas apenas que as outras classes invoquem, ou seja, chamem esses métodos contendo as variáveis da classe produto.


public class Produto {

private Integer idProduto;
private String descricaoProduto;
private Double valorUnitario;
public Produto() {
}
public Integer getIdProduto() {
return idProduto;
}
public void setIdProduto(Integer idProduto) {
this.idProduto = idProduto;
}
public String getDescricaoProduto() {
return descricaoProduto;
}
public void setDescricaoProduto(String descricaoProduto) {
this.descricaoProduto = descricaoProduto;
}
public Double getValorUnitario() {
return valorUnitario;
}
public void setValorUnitario(Double valorUnitario) {
this.valorUnitario = valorUnitario;
}
}

Já a classe “ItemVenda” além de possuir métodos acessores e mutatórios possui um método que obtêm a quantidade de cada produto, através da variável “qtde” e multiplica pela valor unitário de cada produto, informações estas pertencentes à classe produto, veja bem, a classe “ItemVenda” não está instanciando a classe “Produto”, apenas utilizando o método get que obtêm o valor unitário de cada produto.


public class ItemVenda {

private Double qtde;
private Produto produto ;
public ItemVenda() {
}
public Double getValorItemVenda(){
return getQtde()*getProduto().getValorUnitario();
}
public Double getQtde() {
return qtde;
}
public void setQtde(Double qtde) {
this.qtde = qtde;
}
public Produto getProduto() {
return produto;
}
public void setProduto(Produto produto) {
this.produto = produto;
}
}

E como a classe “ItemVenda” possui o método que calcula o valor individual de cada produto, ninguém mais interessada em utilizá-la do que a classe que calcula o total de uma venda, ou seja, a classe “Venda” e agora sim, estamos aplicando o padrão criador, pois a classe “Venda” instancia a classe “ItemVenda” para que esta realize o cálculo.


public class Venda {

private Integer idVenda;
private Date dataVenda;
private Set itemVendaList= new HashSet();

public Venda() {
}
public Integer getIdVenda() {
return idVenda;
}
public void setIdVenda(Integer idVenda) {
this.idVenda = idVenda;
}
public Date getDataVenda() {
return dataVenda;
}
public void setDataVenda(Date dataVenda) {
this.dataVenda = dataVenda;
}
public Double getValorTotal(){
Double valorTotal=0.0;
for(ItemVenda currentItem : itemVendaList){
valorTotal+=currentItem.getValorItemVenda();
}
return valorTotal;
}
public void addItem(ItemVenda i){
itemVendaList.add(i);
}
public void removeItem(ItemVenda i){
itemVendaList.remove(i);
}
public ItemVenda criarItemVenda(Double qtde, Produto produto){
ItemVenda itemVenda = new ItemVenda();
itemVenda.setProduto(produto);
itemVenda.setQtde(qtde);
addItem(itemVenda);
return itemVenda;
}
}

Finalizando, teremos um método main que instancia a classe "Venda" e cada um dos produtos.