BEHAVIOURAL DESIGN PATTERNS
Jann Claude Mousquer1, Kenner Alan Kliemann1, Miguel Diogenes Matrakas2
1Curso de Ciˆencia da Computac¸˜ao – Faculdades Anglo-Americano (FAA) 2Mestrado em Inform´atica Aplicada – Pontif´ıcia Universidade Cat´olica
do Paran´a (PUC-PR) Foz do Iguac¸u, PR - Brasil
{jannclaude,kenner.hp}@gmail.com, mdmatrakas@yahoo.com Abstract. Design patterns make it easier to reuse successful designs and ar-chitectures. Design is a way of interpreting the implementation, analyzing and understanding the interactions between certain parts of the system. And the behavioral patterns are concerned with algorithms and the assignment of res-ponsibility between objects. Describe not only the patterns of objects or classes but also the patterns of communication between them.
Resumo. Design patterns torna mais f´acil reutilizar projetos e arquiteturas bem sucedidas. Design ´e uma forma de interpretar a implementac¸˜ao, analisando e compreendendo as interac¸˜oes entre determinadas partes do sistema. Os pat-terns comportamentais est˜ao preocupados com os algoritmos e as atribuic¸˜oes de responsabilidade entre objetos. Descrevem n˜ao s´o os padr˜oes entre objetos ou classes, mas tamb´em os padr˜oes de comunicac¸˜ao entre eles.
Palavras Chave: Padr˜oes, Design, Software;
1. Introduc¸˜ao
Dificilmente uma empresa consegue sobreviver sem aux´ılio de ferramentas computacio-nais. Algumas organizac¸˜oes necessitam de ferramentas b´asicas como editores de texto, planilhas ou geradores de apresentac¸˜ao enquanto outras necessitam de ferramentas es-pec´ıficas (sistemas corporativos) que contemplem todos os processos administrativos da organizac¸˜ao. Em geral, a complexidade no desenvolvimento e na manutenc¸˜ao de um sis-tema corporativo ´e alta. Essa complexidade aumenta o custo e o tempo para desenvolvˆe-lo e mantˆe-lo.[K19 2012]
Projetar software orientado a objetos ´e dif´ıcil e projeto de software orientado a objetos reutiliz´avel ´e ainda mais. ´E preciso encontrar objetos pertinentes, fator´a-los em classes com a granularidade certa, definir interfaces de classe e hierarquias de heranc¸a e estabelecer relac¸˜oes entre eles. O projeto deve ser espec´ıfico para o problema em quest˜ao, mas tamb´em geral o suficiente para resolver os problemas e necessidades futuras. Vocˆe tamb´em quer evitar redesign, ou pelo menos minimiz´a-lo. Projetistas de software experi-entes ir˜ao lhe dizer que um projeto reutiliz´avel e flex´ıvel ´e dif´ıcil e talvez imposs´ıvel de se obter o “certo” na primeira vez. Antes da conclus˜ao de um projeto, eles costumam tentar reutiliz´a-lo v´arias vezes, modificando-o toda vez.[Gamma et al. 1994]
Padr˜oes de projeto tornam mais f´acil reutilizar projetos e arquiteturas bem su-cedidas. Expressando t´ecnicas comprovadas como padr˜oes de projeto os tornam mais
acess´ıveis aos desenvolvedores dos sistemas. Os padr˜oes de design ajudam a escolher al-ternativas de projetos que tornam um sistema reutiliz´avel e evitam as alal-ternativas que com-prometam a reusabilidade. Padr˜oes de projeto pode at´e mesmo melhorar a documentac¸˜ao e manutenc¸˜ao de sistemas existentes, fornecendo uma especificac¸˜ao expl´ıcita de classe e interac¸˜oes de objetos e sua intenc¸˜ao subjacente. Simplificando, os padr˜oes ajudam um designer `a obter um design ”certo”mais r´apido.[Gamma et al. 1994]
Christopher Alexander diz: ”Cada padr˜ao descreve um problema que ocorre re-petidas vezes em nosso ambiente e ent˜ao descreve o cerne da soluc¸˜ao para esse pro-blema de tal forma que ´e poss´ıvel utilizar esta soluc¸˜ao um milh˜ao de vezes, sem nunca fazer da mesma forma duas vezes”[Alexander et al. 1977]gof. Apesar de Alexander fa-lar sobre padr˜oes em edif´ıcios e cidades, o que ele diz ´e valido sobre design patterns. As soluc¸˜oes s˜ao expressas em termos de objetos e interfaces em vez de paredes e por-tas, mas no cerne de ambos os tipos de padr˜oes ´e a soluc¸˜ao de um problema em um contexto.[Gamma et al. 1994]
De mais a mais, GoF ´e uma abreviac¸˜ao para ”Gang of Four”e refere-se aos quatro escritores do livro ”Design Patterns: Elements of Reusable Object-Oriented Software”. 1.1. Objetivo
Design ´e uma forma de interpretar a implementac¸˜ao, analisando e compreendendo as interac¸˜oes entre determinadas partes do sistema, como poss´ıveis impactos que uma mudanc¸a em um ponto causa em outro componente que o acessa direta ou indiretamente.[Silveira et al. ]. Neste artigo ser´a realizada uma revis˜ao bibliogr´afica dos padr˜oes de projeto (Design Patterns) comportamentais e suas aplicabilidades.
2. Padr˜oes de Projeto
Inicialmente, como descrever padr˜oes de design? Notac¸˜oes gr´aficas, embora importantes e ´uteis, n˜ao s˜ao suficientes. Eles simplesmente capturam o produto final do processo de design como as relac¸˜oes entre classes e objetos. Para reutilizar o design, tamb´em dever´a registrar as decis˜oes alternativas e os trade-offs que levaram a ela. Exemplos concretos s˜ao muito importantes, porque eles ajudam a ver o projeto em ac¸˜ao.[Gamma et al. 1994]
GoF [Gamma et al. 1994] descreve padr˜oes de projeto usando um formato con-sistente. Cada padr˜ao ´e dividido em sec¸˜oes de acordo com um modelo. O modelo d´a uma estrutura uniforme para as informac¸˜oes, tornando os padr˜oes de design mais f´acil de aprender, comparar e usar. O modelo ´e dividido em t´opicos, como por exemplo:
• Nome do padr˜ao e sua classificac¸˜ao; • Intenc¸˜ao. O que ele faz e por que existe; • Aplicabilidade. Onde pode ser aplicado.
Os padr˜oes de design variam na sua granularidade e n´ıvel de abstrac¸˜ao, porquanto h´a muitos padr˜oes de projeto e ´e preciso organiz´a-los. GoF [Gamma et al. 1994]classifica os padr˜oes de projeto por dois crit´erios:
• O primeiro crit´erio chamado de prop´osito, o que um padr˜ao faz. Os padr˜oes podem ser criacionais, estruturais ou comportamentais. Padr˜oes de criac¸˜ao di-zem respeito ao processo de criac¸˜ao do objeto. Padr˜oes estruturais lidam com a composic¸˜ao de classes ou objetos. Os padr˜oes comportamentais se caracterizam pelas classes ou objetos que interagem e distribuem responsabilidades;
• O segundo crit´erio chamado escopo, especifica se o padr˜ao se aplica principal-mente `as classes ou objetos. Padr˜oes de classe lidam com as relac¸˜oes entre as classes e suas subclasses. Essas relac¸˜oes s˜ao estabelecidas por meio de heranc¸a, que est˜ao est´aticos. Padr˜oes de objetos lidam com os relacionamentos de objetos, que podem ser alterados em tempo de execuc¸˜ao, al´em de mais dinˆamicos.
Figura 1. Tabela de Design Patterns segundo GoF
A figura 1 apresenta a tabela de classificac¸˜ao dos padr˜oes de acordo com os crit´erios citados anteriormente.
3. Behavioral patterns
Padr˜oes comportamentais est˜ao preocupados com os algoritmos e as atribuic¸˜oes de res-ponsabilidade entre objetos. Descrevem n˜ao s´o os padr˜oes entre objetos ou classes, mas tamb´em os padr˜oes de comunicac¸˜ao entre eles.
Estes padr˜oes caracterizam um complexo uxo de controle que ´e dif´ıcil de seguir em tempo de execuc¸˜ao. Eles transportam a atenc¸˜ao para longe do uxo de controle e permite ao programador se concentrar apenas no modo como os objetos est˜ao interconec-tados. [Gamma et al. 1994]
A seguir ser˜ao apresentados os padr˜oes e suas caracter´ısticas. 3.1. Chain of responsibility
Evitar o acoplamento do emissor (sender) de um pedido para o seu receptor (receiver), dando mais de um objeto a chance de lidar com o pedido. Cadeia de objetos que recebem e passam a solicitar ao longo desta at´e que um objeto lide com ele.
O padr˜ao resenta ´e um encadeamento de objetos receptores para o processamento de uma s´erie de solicitac¸˜oes diferentes. Esses objetos receptores passam a solicitac¸˜ao ao longo da cadeia at´e que um ou v´arios objetos a tratem.
Cada objeto receptor possui uma l´ogica descrevendo os tipos de solicitac¸˜ao que ´e capaz de processar e ensina como passar adiante aquelas que requeiram processa-mento por outros receptores. A delegac¸˜ao das solicitac¸˜oes pode formar uma ´arvore de recurs˜ao, com um mecanismo especial para inserc¸˜ao de novos receptores no final da ca-deia existente.[Soares 2012]
Um exemplo da aplicac¸˜ao desse padr˜ao ´e o mecanismo de heranc¸a nas lingua-gens orientadas a objeto: um m´etodo chamado em um objeto ´e buscado na classe que implementa o objeto, caso n˜ao seja encontrado na superclasse dessa classe, de maneira recursiva. [Soares 2012]
Figura 2. Chain of Responsability Pattern
A figura 2 representa a estrutra do padr˜ao. Para tanto, tem os seguintes partici-pantes:
• Handler (HelpHandler)
– Define uma interface para controlar requisic¸˜oes; – (Opcional) Implementa o link sucessor.
• ConcreteHandler (PrintButton, PrintDialog) – controle de requisic¸˜ao se poss´ıvel for; – Pode acessar o sucessor;
– se o ContreteHandler consegue controlar a requisic¸˜ao, fac¸a; caso contr´ario tente o pr´oximo.
• Client
– inicia a requisic¸˜ao para um objeto ConcreteHandler.
Quando um cliente emite uma solicitac¸˜ao, o pedido se propaga ao longo da cadeia at´e que um objeto ConcreteHandler assume a responsabilidade de lidar com ele.
O primeiro objeto na cadeia recebe o pedido, manipula-o ou encaminha-o para o pr´oximo candidato na cadeia, que faz o mesmo. O objeto que fez o pedido n˜ao tem conhecimento expl´ıcito de que vai lidar com isso - ´e dito que o pedido tem um receptor impl´ıcito.
Para encaminhar a requisic¸˜ao ao longo da cadeia e garantir os receptores perma-necem impl´ıcitas, cada objeto implementa uma interface comum para o tratamento dos pedidos para acessar o seu sucessor na cadeia.
• Reduc¸˜ao de acoplamento. O padr˜ao libera um objeto de saber que outro objeto manipula uma requisic¸˜ao;
• Maior flexibilidade na atribuic¸˜ao de responsabilidades aos objetos. O padr˜ao ofe-rece mais flexibilidade na distribuic¸˜ao de responsabilidades entre os objetos; • O Recebimento n˜ao ´e garantido. Uma vez que um pedido n˜ao tem receptor
expl´ıcito, n˜ao h´a garantia de que vai ser tratado, o pedido pode sair da cadeia sem nunca ter sido tratado.
Por outro lado, o padr˜ao ´e indicado nos seguintes casos:
• Mais de um objeto pode lidar com uma requisic¸˜ao e o manipulador n˜ao ´e conhe-cido. O manipulador deve ser determinado automaticamente;
• Emiss˜ao de um pedido a um dos v´arios objetos, sem especificar o receptor de forma explicita;
• O conjunto de objetos que podem lidar com um pedido deve ser especificado di-namicamente.
3.2. Command ´
E poss´ıvel encapsular uma requisic¸˜ao como um objeto, permitindo que clientes parame-trizem diferentes requisic¸˜oes, enfileirem ou fac¸am o registro de requisic¸˜oes e suportem operac¸˜oes que podem ser desfeitas.
Al´em disso, controla as chamadas a um determinado componente, modelando cada requisic¸˜ao como um objeto. Permiti ainda que as operac¸˜oes possam ser desfeitas, enfileiradas ou registradas. [K19 2012]
Figura 3. Command Pattern
A figura 3 representa a estrutura do padr˜ao, tendo como participantes, os seguin-tes:
• Command: declara uma interface para executar uma operac¸˜ao. • ConcreteCommand(PasteCommand, OpenCommand)
– Define uma ligac¸˜ao entre um objeto receptor e uma ac¸˜ao;
– Implementa o m´etodo Execute invocando a operac¸˜ao correspondente no receptor.
• Client (Application): cria um objeto ConcreteCommand e o seta como receptor; • Invoker(MenuItem): Pede ao Commanda para executar a solicitac¸˜ao;
• Receiver(Document, Application): sabe como executar as operac¸˜oes de um re-quest. Qualquer classe pode ser um receptor.
No entanto, quando o cliente emite uma requisic¸˜ao de ac¸˜ao, os receptores ir˜ao identificar a solicitac¸˜ao e saber˜ao execut´a-la.
Como consequˆencias, temos:
• O Command desacopla o objeto que invoca a operac¸˜ao daquele que sabe como execut´a-la;
• Commands s˜ao objetos de primeira classe, ou seja, podem ser manipulados e es-tendidos como qualquer outro objeto;
• Um comando pode ser composto por outros comandos;
• ´E f´acil acrescentar novos Commands porque n˜ao ´e preciso mudar classes j´a exis-tentes.
O padr˜ao ´e indicado nos seguintes casos:
• Parametrizar objetos para uma ac¸˜ao a ser tomada;
• Especificar, enfileirar e executar solicitac¸˜oes em tempos diferentes. Um objeto de comando pode ter uma vida independente da solicitac¸˜ao original;
• Suporte a desfazer. O Command pode armazenar as operac¸˜oes de execuc¸˜ao, ar-mazenando seus estados e possibilitando desfazer os mesmos;
• Suporte a mudanc¸as de registro, para que possam ser reaplicadas em caso de uma falha do sistema;
• Estruturar um sistema em torno de operac¸˜oes de alto n´ıvel constru´ıdas sobre operac¸˜oes primitivas. Tal estrutura ´e comum em sistemas de informac¸˜ao que su-portam transac¸˜oes. A transac¸˜ao encapsula um conjunto de alterac¸˜oes aos dados. 3.3. Interpret
Dada uma linguagem, define uma representac¸˜ao para sua gram´atica juntamente com um interpretador que usa a representac¸˜ao para interpretar sentenc¸as na l´ıngua.
Se um determinado tipo de problema ocorre com frequˆencia suficiente, ent˜ao ele pode ser ´util para expressar instˆancias do problema como sentenc¸as em uma linguagem formal. Depois, vocˆe pode construir um int´erprete que resolva o problema por meio da interpretac¸˜ao dessas sentenc¸as, a qual ´e usada para ajudar na aplicac¸˜ao a entender uma declarac¸˜ao de linguagem natural e executar a funcionalidade da declarac¸˜ao.[Soares 2012]
A figura 4 representa a estrutura do padr˜ao e possui os seguintes participantes: • AbstractExpression (RegularExpression): declara um Interpretador de operac¸˜ao
abstrata que ´e comum a todos n´os na ´arvore sint´atica. • TerminalExpression (LiteralExpression)
– Declara uma operac¸˜ao abstrata Interpret que ´e comum a todos n´os na ´arvore sint´atica;
– ´E necess´aria uma instˆancia para cada s´ımbolo terminal da sentenc¸a. • NonterminalExpression (AlternationExpression, RepetitionExpression,
Sequen-ceExpressions)
– Uma classe ´e necess´aria para cada regra n˜ao-terminal na gram´atica; – Mant´em as vari´aveis de instˆancia do tipo AbstractExpression para cada
Figura 4. Interpreter Pattern
– Implementa um Interpret para os simbolos n˜ao-terminais na gram´atica. Interpret normalmente tem chamadas recursivas para vari´aveis que repre-sentam regras n˜ao-terminais.
• Context: Cont´em informac¸˜oes que s˜ao globais para o interpretador. • Client
– Constr´oi (ou ´e fornecido) uma ´arvore de sintaxe abstrata que representa uma sentenc¸a particular na l´ıngua que a gram´atica define. A ´arvore de sintaxe abstrata (AST) ´e montada a partir de instˆancias das classes Nonter-minalExpression e TerNonter-minalExpression;
– invoca a operac¸˜ao Interpret.
O cliente constr´oi (ou ´e fornecido) a sentenc¸a como uma ´arvore de sintaxe abstrata (AST) de instˆancias de NonterminalExpression e TerminalExpression. Em seguida, o cliente inicializa o contexto e invoca a operac¸˜ao Interpret.
Cada n´o NonterminalExpression define Interpret em termos de interpretar em cada sub-express˜ao. A operac¸˜ao Interpret de cada TerminalExpression define o caso base na recurs˜ao.
As operac¸˜oes do Interpret em cada n´o utilizam o contexto para armazenar e acessar o estado do int´erprete.
Como consequˆencias temos:
• Facilidade para alterar e extender gram´aticas. O padr˜ao utiliza classe para repre-sentar regras, as quais podem ser estendidas via heranc¸a;
• Facilidade para implementar gram´aticas. Classes que definem os n´os na ´arvore de sintaxe abstrata tˆem implementac¸˜oes similares. Essas classes s˜ao f´aceis de escrever, e muitas vezes a sua gerac¸˜ao pode ser automatizada com geradores de compilador ou interpretador; muitas vezes a sua gerac¸˜ao pode ser automatizada com geradores de compilador ou interpretador;
• Adic¸˜ao de novas maneiras de interpretac¸˜ao de express˜oes. O padr˜ao Interpreter viabiliza formas f´aceis de avaliar express˜oes.
Por´em, o seguinte item deve ser levado em considerac¸˜ao:
• Gram´aticas complexas s˜ao dif´ıceis de manter. O interpretador define uma classe para cada regra na gram´atica, muitas regras implicam em grandes recursos com-putacionais.
O padr˜ao ´e indicado nos seguintes casos:
• Unicamente para interpretac¸˜ao de linguagens. Como, por exemplo, express˜oes regulares.
3.4. Iterator ´
E fornecer uma maneira de acessar sequencialmente os elementos de um objeto agregado sem expor sua representac¸˜ao subjacente.
Um objeto agregado, como uma lista, deve fornecer uma maneira de acessar seus elementos sem expor sua estrutura interna. Al´em disso, ´e poss´ıvel percorrer a lista de maneiras diferentes.
A ideia do padr˜ao Iterator ´e fornecer um meio eficiente de se percorrer todos os elementos de uma determinada colec¸˜ao.[K19 2012]
Figura 5. Iterator Pattern
A figura 5 representa a estrutura do padr˜ao e tem os seguintes participantes: • Iterator: Define uma interface para atravessar elementos.
• ConcreteIterator
– Implementa a interface Iterator;
– Mant´em a posic¸˜ao do elemento corrente no atravessamento de objetos agregados.
• Aggregate: Define uma interface para criac¸˜ao de um objeto Iterator.
• ConcreteAggregate: Implementa a iterface de criac¸˜ao Iterator para retornar uma instˆancia do correto ConcreteIterator.
O padr˜ao encapsula uma iterac¸˜ao, permitindo acessar os elementos da classe que a implementa independentemente de sua estrutura e organizac¸˜ao.
O ConcreteIterator mant´em o controle do objeto atual e pode calcular o objeto sucessor na travessia.
Como consequˆencias temos:
• Variac¸˜oes diversas na travessia de um agregado; • Simplificac¸˜ao da interface;
• Diversas travessias ao mesmo tempo. Um iterador mant´em o controle de seu pr´oprio estado de travessia.
O padr˜ao ´e indicado nos seguintes casos:
• Acessar o conte´udo de objeto agregados sem expor sua representac¸˜ao interna; • Suporte a mais de uma maneira de percorrer a colec¸˜ao;
• Prover interface ´unica para percorrer estruturas agregadas diferentes. 3.5. Mediator
Um Mediator define um objeto que encapsula como um grupo de objetos interage. Pro-move o desacoplamento, mantendo referˆencias expl´ıcitas entre os objetos e permite variar suas interac¸˜oes de forma independente.
Projetos de software orientado a objetos incentivam a distribuic¸˜ao de comporta-mento entre os objetos. Essa distribuic¸˜ao pode resultar em uma estrutura de objetos com muitas conex˜oes e acoplamento entre objetos. No pior caso, cada objeto acaba sabendo sobre todos os outros.
Quanto mais classes houver no seu projeto, a comunicac¸˜ao entre essas classes ser´a mais complexa. Isso faz com que a leitura e a manutenc¸˜ao do programa fiquem mais dif´ıcil, tal situac¸˜ao acarreta na dificuldade de mudanc¸as no projeto, j´a que, uma simples mudanc¸a pode afetar todo o c´odigo e as outras classes.[Soares 2012]
Com o padr˜ao mediator, a comunicac¸˜ao entre os objetos ´e encapsulada com um objeto mediador. Isso reduz a dependˆencia entre os objetos que est˜ao se comunicando.[Soares 2012] A ideia do padr˜ao Mediator ´e semelhante `a ideia de central telefˆonica. Eliminar conex˜oes excessivas entre elementos por meio da introduc¸˜ao de um intermedi´ario ´unico.[K19 2012]
A figura 6 representa a estrutura do padr˜ao e tem os seguintes participantes: • Mediator: Define uma interface para comunicac¸˜ao com objetos Colleague. • ConcreteMediator (FontDialogDirector)
– Implementa o comportamento cooperativo, por meio da coordenac¸˜ao ob-jetos Colleague;
– Conhece e mant´em seus colegas. • Colleague classes (ListBox, EntryField)
– Cada classe Colleague conhece seu Mediator;
– Cada objeto Colleague se comunica com o Mediator ao inv´es de outros Colleagues.
Figura 6. Mediator Pattern
Um objeto Mediador deve encapsular toda a comunicac¸˜ao entre um grupo de ob-jetos. Cada objeto participante conhece o mediador, mas ignora a existˆencia dos outros objetos.
O mediador conhece cada um dos objetos participantes e a interface do Mediador ´e usada para iniciar a comunicac¸˜ao e receber notificac¸˜oes. O mediador recebe requisic¸˜oes dos remetentes e repassa as requisic¸˜oes aos destinat´arios
Como consequˆencias temos:
• Desacoplamento entre os diversos participantes da rede de comunicac¸˜ao (partici-pantes n˜ao se conhecem); de comunicac¸˜ao (partici(partici-pantes n˜ao se conhecem) • Eliminac¸˜ao de relacionamentos muitos para muitos (s˜ao todos substitu´ıdos por
relacionamentos um para muitos); • Abstrai como os objetos se comunicam;
• A pol´ıtica de comunicac¸˜oes est´a centralizada no mediador e podem ser alterados sem alter os Colleagues.
O padr˜ao ´e indicado nos seguintes casos:
• Um conjunto de objetos se comunica de maneiras bem definidas, mas complexas. As interdependˆencias resultantes s˜ao n˜ao estruturadas e de dif´ıcil compreens˜ao; • Reutilizac¸˜ao de um objeto ´e dif´ıcil porque ele se refere e se comunica com muitos
outros objetos;
• Um comportamento que ´e distribu´ıdo entre v´arias classes deve ser personaliz´avel sem criar diversas subclasses.
3.6. Memento
Sem violar o encapsulamento, captura e externaliza o estado interno de um objeto para que o objeto possa ser restaurado mais tarde.
Captar e externalizar um estado interno de um objeto, de maneira que esse estado seja restaurado ao objeto em outro momento, sem violar seu encapsulamento.[Soares 2012]
A maneira mais comum de guardar informac¸˜oes dessa maneira ´e por meio de um clone do objeto, instanciado com as informac¸˜oes do estado a ser guardado.[Soares 2012]
Figura 7. Memento Pattern
• Memento (SolverState)
– Salva o estado interno do objeto Originator; – Protege o acesso dos objetos.
• Originator (ConstraintSolver) – Cria um snapshot do objeto;
– Usa o Memento para restaurar o objeto. • Caretaker (undo mechanism)
– ´E respons´avel por manter o Memento;
– Nunca altera ou examina o conte´udo do Memento.
Um Caretaker solicita um snapshot de um objeto e passa o resultado para o Me-mento manter.
Como consequˆencias temos:
• Preserva limites do encapsulamento; • Simplifica o Originator;
• Definic¸˜ao de interfaces estreitas e largas. Pode ser dif´ıcil em algumas linguagens para garantir que apenas o criador pode acessar o estado do memento.
O padr˜ao ´e indicado nos seguintes casos: • Na implementac¸˜ao de ac¸˜oes de “desfazer”;
• Para o armazenamento de estados a serem restaurados de um objeto, como por exemplo, um banco de dados;
• Para a captac¸˜ao de estados de objetos que s˜ao encobertos por encapsulamento. 3.7. Observer
Define uma dependˆencia um-para-muitos entre objetos de modo que quando um objeto muda de estado, todos os seus dependentes s˜ao notificados e atualizados automaticamente. Permite que objetos interessados sejam avisados da mudanc¸a de estado ou outros eventos ocorrendo num outro objeto. O padr˜ao Observer ´e tamb´em chamado de Publisher-Subscriber, Event Generator e Dependents.[Soares 2012]
A ideia fundamental do padr˜ao Observer ´e atribuir aos objetos que tem seus esta-dos alteraesta-dos a tarefa de notificar os objetos interessaesta-dos nessas mudanc¸as.[K19 2012]
Figura 8. Observer Pattern
• Subject
– Conhece seus observers. Quaisquer n´umeros de observers podem observar um subject;
– Disponibiliza uma interface para anexar e desanexar objetos observers. • Observer: Define uma interface de atualizac¸˜ao para os objetos que devem ser
notificados sobre mudanc¸as no subject. • ConcreteSubject
– Armazena o estado por qual os ConcreteObservers tˆem interesse; – Envia uma notificac¸˜ao aos seus observers sempre que este estado muda. • ConcreteObserver
– Mant´em referˆencia(s) para o(s) ConcreteSubject(s) sendo observado(s); – Armazena o estado que deve ser mantido consistente com o estado do
sub-ject;
– Implementa a interface de atualizac¸˜ao do Observer.
O ConcreteSubject notifica seus observers sempre que uma mudanc¸a (que pode tornar o estado do observer inconsistente) ocorrer.
Depois de informado sobre uma mudanc¸a no ConcreteSubject o ConcreteObser-ver pode consultar o ConcreteSubject e utilizar a informac¸˜ao obtida para reconciliar seu estado com o estado do ConcreteSubject.
Como consequˆencias temos:
• Acoplamento abstrato entre o Subject e Observer; • Suporte para comunicac¸˜ao em broadcast.
Mas deve-se atententar ao detalhe: • Atualizac¸˜oes inesperadas;
– Devido ao fato que observers n˜ao conhecem a presenc¸a de outros observers eles n˜ao tˆem ciˆencia do custo final de atualizac¸˜ao de um subject;
– Um protocolo muito simples de atualizac¸˜ao (sem parˆametros) pode fazer com que os observers tenham que realizar muito trabalho para deduzir o que mudou.
• Quando uma abstrac¸˜ao possui dois aspectos, um dependente do outro. Encapsular estes aspectos em objetos diferentes permite que vocˆe os modifique e reutilize de forma independente;
• Quando uma mudanc¸a em um objeto requer a mudanc¸a em outros e vocˆe n˜ao sabe quantos e quais objetos precisam ser modificados. Ou seja, n˜ao se deseja um alto acoplamento entre estes objetos.
3.8. State
Permitir que um objeto altere o seu comportamento como consequˆencia de uma mudanc¸a no seu estado interno.
Considerando uma classe TCPConnection que representa uma conex˜ao de rede. Um objeto TCPConnection pode estar em um dos v´arios estados diferentes: Established, Listening, Closed.. Quando um objeto TCPConnection recebe pedidos de outros objetos, ele responde de forma diferente, dependendo do seu estado atual.
Figura 9. State Pattern
A figura 9 representa a estrutura do padr˜ao e tem os seguintes participantes: • Context (TCPConnection)
– Define a interface de interesse dos clientes;
– Mant´em uma instˆancia do ConcreteState que define o estado atual do con-texto.
• State (TCPState): Define uma interface que encapsula o comportamento associado a um estado particular do contexto.
• ConcreteState subclasses (TCPEstablished, TCPListen, TCPClosed): Cada sub-classe implementa o comportamento associado com o estado do contexto que ela representa.
O Context delega requisic¸˜oes espec´ıficas de estado ao ConcreteState atual e, ainda, pode passar ele pr´oprio como argumento para o objeto State atendendo a requisic¸˜ao. O Context ´e a interface prim´aria para clientes. Clientes configuram o Context com objetos State.
O Context ou as subclasses ConcreteState podem decidir qual estado sucede outro e em quais circunstˆancias. Como consequˆencias temos:
• Localiza o comportamento espec´ıfico para os diferentes estados; • Faz com que as transic¸˜oes se tornem expl´ıcitas;
• Objetos State podem ser compartilhados. O padr˜ao ´e indicado nos seguintes casos:
• Quando o comportamento do objeto depende do seu estado e este comportamento deve ser modificado em run-time;
• Quando os m´etodos possuem sentenc¸as condicionais grandes e com v´arias opc¸˜oes. O padr˜ao State coloca cada ramo da sentenc¸a condicional em uma classe separada. 3.9. Strategy
Definir uma fam´ılia de algoritmos, encapsular cada um e torn´a-los intercambi´aveis. Es-trat´egia permite que o algoritmo varie independentemente dos clientes que o utilizam.
Existem muitos algoritmos para quebrar um fluxo de texto em linhas.
N˜ao ´e desej´avel acoplar estes algoritmos para as classes que necessitam deles.
Figura 10. Strategy Pattern
A figura 10 representa a estrutura do padr˜ao e tem os seguintes participantes: • Strategy (Compositor)
– Declara uma interface comum a todos os algoritmos suportados;
– O Context utiliza esta interface para chamar um algoritmo definido por um ConcreteStrategy.
• ConcreteStrategy (SimpleCompositor, TeXCompositor, ArrayCompositor): Im-plementa o algoritmo utilizando a interface Strategy.
• Context (Composition)
– ´E configurado com um ConcreteStrategy; – Mant´em uma referˆencia para o objeto Strategy;
– Pode definir uma interface que permite que os ConcreteStrategies acessem seus dados;
O Strategy e o Context interagem para implementar o algoritmo escolhido. O Context pode passar todos os dados necess´arios `a execuc¸˜ao do algoritmo ou o Context passa ele pr´oprio como argumento da operac¸˜ao, permitindo que o Strategy consulte os dados necess´arios.
Um Context repassa requisic¸˜oes do cliente para o seu Strategy. O cliente geral-mente cria e configura o Context com um ConcreteStrategy e passa a interageir sogeral-mente com o Context.
Como consequˆencias temos:
• Fam´ılia de algoritmos relacionados;
• Uma alternativa a sub-classing. Pode-se derivar o Contexto para prover diferentes implementac¸˜oes;
• As Strategies eliminam declarac¸˜oes condicionais. O padr˜ao ´e indicado nos seguintes casos:
• Quando muitas classes relacionadas diferem somente no seu comportamento; • Quando ´e necess´ario utilizar diferentes variac¸˜oes de um algoritmo;
• Quando um algoritmo utiliza dados que n˜ao devem estar expostos aos clientes; • Quando uma classe define m´ultiplos comportamentos atrav´es de sentenc¸as
condi-cionais em seus m´etodos. 3.10. Template Method
Definir o esqueleto de um algoritmo em uma operac¸˜ao, adiando alguns passos para sub-classes. Template Method permite que subclasses redefinam determinadas etapas de um algoritmo sem alterar a estrutura do algoritmo.
A ideia fundamental desse padr˜ao ´e definir a ordem de execuc¸˜ao dos passos que resolvem um determinado problema e permitir que cada passo possa ser implementado de maneiras diferentes.[K19 2012]
Figura 11. Template Method Pattern
A figura 11 representa a estrutura do padr˜ao e tem os seguintes participantes: • AbstractClass (Application)
– Declara operac¸˜oes primitivas abstratas a serem definidas por sub-classes ao implementar os passos do algoritmo;
– Implementa o Template Method definindo o arcabouc¸o do algoritmo. Este Template Method invoca tanto as operac¸˜oes primitivas quanto operac¸˜oes concretas de AbstractClass ou de outros objetos.
• ConcreteClass (MyApplication): Implementa as operac¸˜oes primitivas, executando os passos do algoritmo espec´ıficos desta subclasse.
ConcreteClass depende de AbstractClass para implementar as medidas invariantes do algoritmo.
Como consequˆencias temos:
• Template Methods ´e uma t´ecnica fundamental para a reutilizac¸˜ao de c´odigo. Esta t´ecnica ´e particularmente importante em bibliotecas de classes, porque ela ´e o meio para fabricar um comportamento comum em classes de bibliotecas.
• Template Methods podem invocar os seguintes tipos de m´etodos:
– Operac¸˜oes concretas (da sua pr´opria classe ou de outros objetos); – Operac¸˜oes primitivas (m´etodos abstratos);
– Factory Methods;
– M´etodos hook (m´etodos de AbstractClass com implementac¸˜oes default mas que podem ser sobrepostos pelas sub-classes).
O padr˜ao ´e indicado nos seguintes casos:
• Implementac¸˜ao ´unica das partes invariantes de um algoritmo e deixar que subclas-ses implementem o comportamento que varia;
• Quando um comportamento comum entre subclasses deve ser fatorado e locali-zado em uma classe comum, com o objetivo de evitar repetic¸˜ao de c´odigo;
• Para controlar as extens˜oes realizadas pelas subclasses. O Template Method pode definir operac¸˜oes hook em pontos espec´ıficos e, portanto, permitindo variac¸˜oes somente nestes locais.
3.11. Visitor
Representar uma operac¸˜ao a ser realizada sobre os elementos de uma estrutura de objeto. Visitor permite que vocˆe defina uma nova operac¸˜ao sem mudar as classes dos elementos sobre os quais opera.
Permite atualizac¸˜oes espec´ıficas em uma colec¸˜ao de objetos de acordo com o tipo particular de cada objeto atualizado.[K19 2012]
A figura 12 representa a estrutura do padr˜ao e tem os seguintes participantes: • Visitor (NodeVisitor)
– Declara uma operac¸˜ao visit() para cada classe de ConcreteElemente pre-sente no agregado;
– O nome e a assinatura da operac¸˜ao visit() identifica a classe que solicita a execuc¸˜ao do visit() no Visitor;
– Isto permite que o Visitor determine a classe concreta do elemento sendo visitado e se comunique diretamente com ele.
• ConcreteVisitor (TypeCheckingVisitor)
– Implementa cada operac¸˜ao declarada no Visitor;
– Cada operac¸˜ao implementa o fragmento do algoritmo espec´ıfico da classe em quest˜ao;
Figura 12. Visitor Pattern
– O ConcreteVisitor disponibiliza o contexto para o algoritmo e geralmente armazena estado local que acumula resultados durante a varredura do agre-gado.
• Element (Node): Declara a operac¸˜ao accept() que recebe o visitor como parˆametro.
• ConcreteElement (AssignmentNode,VariableRefNode): Implementa a operac¸˜ao accept().
• ObjectStructure (Program)
– Pode enumerar seus elementos;
– Pode disponibilizar uma interface de alto n´ıvel para permitir que o Visitor visite seus elementos;
– Pode ser ou um Composite ou uma collection como uma lista ou conjunto. Um cliente que usa o padr˜ao Visitor deve criar um objeto ConcreteVisitor e, em seguida, atravessar a estrutura do objeto, visitando cada elemento.
Quando um elemento ´e visitado, ele chama a operac¸˜ao o Visitor que corresponde a sua classe.
O elemento em si fornece ´e um argumento para esta operac¸˜ao para deixar seu estado ao Visitor, se necess´ario.
Como consequˆencias temos:
• O Visitor torna f´acil a adic¸˜ao de novas operac¸˜oes;
• O Visitor agrupa operac¸˜oes relacionadas e separa as n˜ao-relacionadas; • O Visitor torna dif´ıcil a adic¸˜ao de novos ConcreteElements;
• Com o Visitor os objetos visitados n˜ao precisam ter um ancestral comum;
• Acumulando estado. Visitors podem acumular estado `a medida em que visitam os elementos. Sem o Visitor este estado seria passado como parˆametro das operac¸˜oes que realizam a varredura ou declarado atrav´es de vari´aveis globais;
• Quebrando o encapsulamento. Ao utilizar o Visitor assume-se que a interface do ConcreteElement ´e poderosa o suficiente para permitir que o Visitor fac¸a o seu trabalho.
O padr˜ao ´e indicado nos seguintes casos:
• Quando um agregado cont´em objetos de diversas classes (com diferentes interfa-ces) e deseja-se realizar operac¸˜oes nestes objetos que dependem das suas classes concretas;
• Quando muitas operac¸˜oes distintas e n˜ao relacionadas precisam ser aplicadas a um agregado e n˜ao se deseja poluir as classes dos objetos do agregado com tais operac¸˜oes;
• Quando as classes que definem os objetos do agregado raramente mudam, por´em definem-se novas operac¸˜oes com certa frequˆencia.
4. Conclus˜ao
Padr˜oes de projeto s˜ao otimizados, sendo as soluc¸˜oes reutiliz´aveis para os problemas de programac¸˜ao que nos deparamos todos os dias. Um padr˜ao de design n˜ao ´e uma classe ou uma biblioteca que podemos simplesmente plugar em nosso software; ´e muito mais do que isso. ´E um molde que tem de ser aplicada na situac¸˜ao correta. Tamb´em n˜ao ´e espec´ıfico de linguagem. Um padr˜ao de design bom deve ser implement´avel na maioria (se n˜ao em todas) as linguagens, dependendo de seus recursos. Ainda, qualquer padr˜ao de design pode ser uma faca de dois gumes, pois se implementado no lugar errado pode ser desastrosa e criar muitos problemas. No entanto, implementado no lugar certo, na hora certa, ele pode ser a soluc¸˜ao.[Bautista 2010]
Design patterns devem ter seu uso planejado, devemos lembrar sempre da m´axima:
Se est´as com dor de cabec¸a, n˜ao ir´as tomar dez comprimidos de dorflex!
4.1. Trabalhos futuros
Design de software n˜ao ´e limitado `a arquitetura e estruturas, podem ser aplicados `a forma que o c´odigo ´e escrito, organizado, sua legibilidade e complexidade.
• Anti-patterns: s˜ao determinados padr˜oes de desenvolvimento de software que s˜ao considerados uma m´a pr´atica de programac¸˜ao.
• Refactoring Com a refatorac¸˜ao, os programadores podem transformar at´e mesmo o software mais ca´otico em sistemas bem desenhados que s˜ao muito mais f´aceis de evoluir e manter. Refatorac¸˜ao ´e uma t´ecnica controlada para melhorar o de-senho de uma base de c´odigo existente. Sua essˆencia ´e a aplicac¸˜ao de uma s´erie de pequenas transformac¸˜oes que preservam o comportamento, refatorac¸˜ao ´e est´ar aperfeic¸oando a qualidade do c´odigo.
Referˆencias
Alexander, C., Ishikawa, S., Silverstein, M., Jacobson, M., Fiksdahl-King, I., and Angel, S. (1977). A Pattern Language. Oxford University Press.
Gamma, E., Helm, R., Johnson, R., and Vlissides, J. (1994). Design Patterns: Elements of Reusable Object-Oriented Software. Pearson Education.
K19 (2012). Design Patterns em Java.
Silveira, P., Silveira, G., Lopes, S., Moreira, G., Steppat, N., and Kung, F. Introduc¸˜ao ´a Arquitetura de Design de Software. Elsevier Brasil.