PADRÕES DE PROJETO. capítulo seis

Tamanho: px
Começar a partir da página:

Download "PADRÕES DE PROJETO. capítulo seis"

Transcrição

1 capítulo seis PADRÕES DE PROJETO Desenvolver software é considerado uma tarefa árdua. E não faltam razões para essa afirmação. Se considerarmos que na medida em que os problemas crescem em complexidade, aumenta também o número de soluções possíveis, temos aí um grande desafio: qual, dentre as soluções que vislumbramos, devemos escolher? A busca pela melhor solução, antes mesmo de efetivamente termos resolvido o problema, usualmente traz mais dificuldades ao processo de desenvolvimento. Knuth 1 (1968) simplesmente diria que a otimização prematura é a raiz de todo mal. Como muitos dos projetistas de tecnologia e desenvolvedores parecem limitar o conjunto de alternativas visíveis a uma estreita faixa de soluções esboçadas pela comunidade técnica onde se inserem (Jensen & La Porte, 1996), simplesmente muitas tecnologias novas e soluções deixam de surgir. Na maioria dos casos, notamos que o entendimento do problema não é absolutamente claro: é comum que a documentação esteja incompleta, e às vezes ausente, quanto ao problema em si e à solução encontrada para ele. Dessa maneira, problemas idênticos, que se repetem em outros contextos, não são reconhecidos como tal, consumindo tempo e recursos para a implementação de soluções que já haviam sido encontradas. Atualmente o desenvolvimento de software faz uso intenso da orientação a objetos, que permite, em tese, agregar aos sistemas assim desenvolvidos as seguintes qualidades: confiabilidade, robustez, distributividade, armazenabilidade, extensibilidade e reusabilidade (Page-Jones, 2001, p. 68). Mas o uso da orientação a objetos, por si só, não garante a obtenção dessas qualidades e parece depender muito mais das técnicas usadas nas etapas de análise e projeto desses sistemas do que realmente das linguagens e ferramentas empregadas no desenvolvimento e teste, evidenciando as questões relacionadas à compreensão do problema e sua documentação. Os padrões de projeto, também conhecidos como design patterns, vem despertando o interesse da comunidade de projetistas de software por permitir não apenas a documentação de problemas e suas soluções, mas por proporcionar elementos que conduzem ao reaproveitamento do projeto dessas soluções, possibilitando que os sistemas construídos sob essa orientação exibam as qualidades desejadas. 1. Donald E. Knuth é um dos maiores cientistas da computação de que se tem notícia, tendo colaborado em diversas áreas, entre elas, programação, algoritmos e sistemas operacionais. 06.pmd /12/02, 16:17

2 MAIS JAVA Como motivação adicional, toda a plataforma Java faz uso intensivo dos padrões de projeto, ou seja, depois de estudados os padrões, reconheceremos com facilidade onde foram aplicados nas diversas classes da API, reforçando algo que já sabíamos: o quanto o Java é moderno e adequado para o desenvolvimento de software orientado a objetos. 6.1 O que são os padrões de projeto? Existem várias definições para os padrões de projeto. Tomemos uma dessas definições, hoje considerada clássica, proveniente do grupo conhecido como Go (Gang of our): Um padrão de projeto sistematicamente nomeia, motiva e explica um projeto genérico, que endereça um problema de projeto recorrente em sistemas orientados a objetos. Ele descreve o problema, a solução, quando é aplicável e quais as conseqüências de seu uso. [Tradução livre] (Gamma, Helm, Johnson & Vlissides, 1995, p. 360) 406 Nessa definição, vemos enfatizadas as questões do entendimento do problema e da solução, da ocorrência do problema repetidas vezes e de sua aplicabilidade, motivando o projeto na direção de uma solução genérica. Cada padrão de projeto é então o responsável por um tipo de problema, que pode ocorrer repetidas vezes em nosso ambiente, e pela sua solução, de modo que possamos reutilizá-lo. Dessa maneira, certas soluções, que foram utilizadas em situações particulares, podem ser novamente usadas por outros desenvolvedores em situações semelhantes. A visão de Coplien do conceito de padrão de projeto é similar: Um padrão (de projeto) é uma peça de literatura que descreve um problema de projeto e a solução geral para o problema em um contexto particular. [Tradução livre] (Coplien, 1996, p. 2) Embora existam várias formas propostas para a descrição de padrões de projetos, todas exigem que os problemas e as soluções envolvidos sejam documentados de maneira estruturada, criando uma cultura de catalogação de experiências e soluções que auxiliem o desenvolvimento de novos softwares. Vejamos uma outra definição: Padrões de projeto capturam a experiência na construção de software orientado a objetos. [Tradução livre] (Budinsky, innie, Vlissides & Yu, 1996) Sendo o desenvolvimento de software uma tarefa reconhecidamente difícil, a experiência (enquanto essência das habilidades desenvolvidas ao longo do tempo em uma área específica) torna-se inestimável. Idealmente gostaríamos que os projetistas mais experientes pudessem 06.pmd /12/02, 16:17

3 Capítulo 6: Padrões de projeto compartilhar tal conhecimento com os novatos, não apenas acelerando seu amadurecimento profissional, mas ampliando as chances do surgimento de soluções inovadoras, de novas técnicas e metodologias de trabalho. Mas tal transferência de experiências é outro desafio existente na comunidade dos projetistas e desenvolvedores de software. Uma tática usada pelos projetistas é evitar a construção de soluções do início ao fim, isto é, entendido o problema, devem ser identificadas as partes semelhantes a sistemas já existentes e proceder-se sua reutilização. Também é comum que, a cada ciclo de uso de uma solução, sejam incorporadas novas características que aperfeiçoem ou generalizem a solução encontrada. Mas isso só pode ser feito por projetistas experientes, que já tenham passado por tais experiências, e desde que os problemas e soluções sejam documentados (o que não é uma tarefa considerada agradável). Como muitas das metodologias de projeto acabam por focar excessivamente a solução em si, descrevendo muito precisamente o que e como deve ser feito, deixando de lado o por que da solução (Kent & Johnson, 1994, p. 139), a documentação produzida pode não ser efetivamente útil. Não se trata de desvalorizar a importância das técnicas de projeto e da documentação das soluções, mas o entendimento do problema é a chave das questões aqui apresentadas em relação às dificuldades do desenvolvimento e também do compartilhamento do conhecimento adquirido com as soluções encontradas. Mais importante que a solução em si é a clara descrição do problema e da forma com que uma solução se torna aplicável, incluindo-se aí as limitações e as conseqüências do emprego dessa solução. Os padrões de projeto pretendem preencher essas lacunas, tornando-se um mecanismo eficiente para a comunicação e o compartilhamento de conhecimento entre os desenvolvedores. A idéia é a criação de uma linguagem comum, capaz de exprimir mais do que simples estruturas de dados, módulos, rotinas ou objetos, mas a articulação desses elementos em soluções arquitetônicas para o software. Ao mesmo tempo, os padrões de projeto não se prendem a linguagens de programação ou contextos particulares, permitindo a catalogação de soluções testadas e aprovadas permitindo sua reutilização. Os padrões de projeto devem ser capazes de exibir a racionalidade existente em uma proposta de solução (Budinsky, innie, Vlissides & Yu, 1996) compondo um vocabulário para discussão e aperfeiçoamento das questões relacionadas ao desenvolvimento de software orientado a objetos. Ao citar-se um padrão de projeto, todo um conjunto de conceitos, relativo a um problema e sua solução, são implicitamente associados, permitindo a discussão em um elevado nível de abstração. 407 Sendo assim, os padrões de projeto tornam-se um mecanismo fundamental para a expressão de projetos de software e, portanto, do entendimento amplo de certos problemas de projeto. Exibem como principais características a possibilidade de reutilização dos projetos em si (e não apenas do código usado em suas implementações) e a definição de uma linguagem de análise e discussão de problemas e soluções de projeto, proporcionando economia de tempo, compartilhamento efetivo de experiências e construção de sistemas melhores. EDITORA FUTURA 06.pmd /12/02, 16:17

4 MAIS JAVA Ainda citando Go : Padrões de projeto identificam, denominam e abstraem temas comuns do projeto orientado a objetos. Eles preservam a informação do projeto capturando a intenção anterior ao projeto. Eles identificam classes, instâncias, seus papéis, colaborações e a distribuição das responsabilidades. [Tradução livre] (Gamma, Helm, Johnson & Vlissides, 1993, p. 408) Nesse sentido, os padrões de projeto são modelos de soluções relacionados a problemas específicos, mas que ocorrem em inúmeros e diferentes contextos. Por meio deles, o entendimento das questões envolvidas é mais amplo, as possibilidades de aplicação bem como os compromissos e limitações existentes são melhores caracterizados; portanto, à medida que um projetista se familiariza com diferentes padrões de projeto, é possível que o mesmo adquira uma parcela da experiência daqueles que desenvolveram e documentaram tais padrões. O emprego de tais padrões aos projetos evita que as soluções existentes, já testadas e aprovadas, venham a ser reinventadas, permitindo a concentração de esforços nos aspectos inéditos do problema e tornando os sistemas assim desenvolvidos provavelmente mais robustos e confiáveis. 6.2 Um breve histórico 408 As idéias que deram origem aos padrões de projeto ocorreram em um contexto muito diferente da área de engenharia de software. Em 1977, o arquiteto Christopher Alexander e seus colegas publicaram o livro A pattern language, uma espécie de catálogo com 253 padrões construtivos, defendendo que os métodos tradicionais empregados pela arquitetura não supriam as reais necessidades dos usuários das construções propostas e, portanto, que a arquitetura não atendia a sociedade como deveria, pois seu maior objetivo é melhorar a qualidade de vida das pessoas. Cada um dos padrões apresentados era como um pequeno manual sobre uma questão arquitetônica comum (Alexander et al., 1977, Lea, 1994), onde o conceito central de padrão é: Cada padrão descreve um problema que ocorre outra e mais outra vez no nosso ambiente, e então descreve o âmago da solução desse problema, de forma que você possa usar essa solução um milhão de vezes, sem fazer o mesmo duas vezes. [Tradução livre] (Alexander et al., 1977) Em 1979, Alexander publica A timeless way of building, onde formaliza método e o elemento racional de suas idéias publicadas anteriormente, descrevendo um padrão como: Cada padrão é uma regra com três partes, que expressa uma relação entre um certo contexto, um problema e uma solução. [Tradução livre] (Alexander, 1979, p. 247) 06.pmd /12/02, 16:17

5 Capítulo 6: Padrões de projeto Nesses livros, Alexander defendia que o uso de padrões não limitaria os arquitetos às soluções prescritas, mas garantiria a presença dos elementos fundamentais que levam ao conforto, articulando função e forma nas construções e nos ambientes ali existentes, integrando-os à natureza, pois tais padrões exprimiam conceitos atemporais de qualidade. Vários anos depois, Ward Cunnigham e Kent Beck, trabalhando em um projeto envolvendo desenvolvimento de interfaces de usuário e inspirados pelas idéias de Alexander, propõem cinco padrões, implementados em Smalltalk 2, que proporcionaram grandes ganhos ao projeto. Esses padrões e algumas conclusões foram apresentados em 1987 na OOPSLA (Object-Oriented Programming Systems, Languages and Applications). Erich Gamma, em um trabalho paralelo durante sua tese de doutorado, nota a importância do uso de padrões repetitivos em projetos. Em uma conferência integrada da OOPSLA e ECOOP (European Conference on Object-Oriented Programming), em 1990, Gamma, em conjunto com Bruce Anderson e Richard Helm, discute sobre padrões. Em uma série de conferências sobre orientação a objetos que se sucederam, o tema começou a ganhar mais espaço e mais adeptos, entre eles: James Coplien, Ralph Johnson, John Vlissides, Desmond D Souza, Douglas Lea, Norm Kerth e Wolfgang Pree. Livros e inúmeros artigos começam a ser publicados divulgando o assunto, tal como Advanced C++ programming styles and idioms (Coplien, 1992). Após um workshop patrocinado pela IBM, em maio de 1993, no qual muitos dos pesquisadores citados se encontraram, Kent Beck e Grady Booch organizaram um retiro no Colorado (Estados Unidos), reunindo um grande número de estudiosos. A partir desse evento, esse grupo começou a manter contato freqüente e a autodenominar-se The hillside group, hoje uma instituição independente dedicada ao estudo dos padrões de projeto. Uma conferência específica, a PLoP (Pattern Languages of Programming) é organizada por membros do grupo em 1994, repetindo-se várias outras vezes nos anos seguintes. Logo após a Gang of four, publica seu compêndio sobre padrões: Design patterns: elements of reusable object-oriented software (Gamma, Helm, Johnson & Vlissides, 1995), uma referência absoluta no tema (embora infelizmente só contenha exemplos em C++ e Smalltalk). 409 Um outro grupo, às vezes referenciado como Gang of five, composto por rank Buschmann, Regine Meunier, Hans Rohnert, Peter Sommerlad e Michael Stal, publicou o livro Pattern-oriented software architecture, outra importante e conhecida referência. A partir daí o tema design patterns, ou seja, os padrões de projeto, tornam-se uma coqueluche, pois trouxe uma proposta concreta para expressar não apenas estruturas de projetos, mas retratar a essência de soluções de problemas comuns, representando um novo e rico vocabulário para troca de experiências e discussões sobre engenharia de software e desenvolvimento de sistemas orientados a objetos. 2. Linguagem e ambiente de programação orientada a objeto, que surgiu por volta de 1970 e é considerada por muitos como uma implementação pura da orientação a objetos. EDITORA FUTURA 06.pmd /12/02, 16:17

6 MAIS JAVA 6.3 Características dos padrões de projeto Os padrões de projeto possuem algumas características importantes que devem ser destacadas (Lea, 1994, Gamma et al., 1995, Coplien, 1996): ± Os padrões de projeto devem descrever e justificar as soluções para problemas concretos e bem definidos, isto é, não são estratégias ou princípios de implementação. ± As soluções descritas devem estar comprovadas, isto é, devem ter sido previamente experimentadas e testadas. ± O problema tratado por um padrão deve ocorrer em diferentes contextos, ou seja, se a solução não tem aplicação em diferentes situações então não constitui um padrão. ± Usualmente os padrões de projeto descrevem relações entre conceitos, mecanismos e estruturas existentes nos sistemas. ± Os padrões devem ser capazes de capturar a evolução e o aprimoramento das soluções, assim como equilibrar os pontos fortes e fracos encontrados, sendo assim não são soluções óbvias ou triviais. ± Os padrões devem ser utilizados em conjunto com outros padrões, compondo linguagens de padrões (pattern languages). 410 Assim, podemos afirmar que o conceito de padrão de projeto é mais amplo e talvez mais adequado que o de classe, empregado na orientação a objetos, pois permite exprimir adequadamente conceitos e estruturas existentes que não são necessariamente objetos. inalmente, os padrões devem ser úteis, no sentido de reunir as experiências em torno da solução de um problema, e utilizáveis, oferecendo elementos que possibilitem seu emprego efetivo. 6.4 Descrevendo padrões de projeto Para que os padrões possam ser usados como um vocabulário específico para projetistas de software e depois catalogados como dicionários de soluções, devem ser descritos adequadamente. Como não são implementações, mas soluções de alto nível, são descritos textualmente, de modo a caracterizar o problema, o contexto onde este ocorre, sua análise e a solução proposta (Coplien, 1996, p. 7). Considerando que descrições textuais podem ser estruturadas de inúmeras maneiras, é interessante a utilização de um roteiro que oriente quais elementos devem ser documentados, facilitando sua utilização e entendimento. Existem diversas formas, entre elas algumas mais populares: Alexander (Alexander, 1977, p. X-XI), Go (Gamma, et al., 1995, p. 6-7), Portland (Cunningham, 2002) ou Coplien (Coplien, 1996, p. 14). Essencialmente essas formas incluem nome do padrão de projeto, propósito, problema, contexto, dificuldades, limitações ou restrições, solução, resultados, esboços e exemplos. 06.pmd /12/02, 16:17

7 Capítulo 6: Padrões de projeto A forma Go é muito objetiva, organizada e dirigida à produção de software orientada a objetos, sendo muito adequada para a elaboração de um catálogo de padrões. Ela tem a seguinte estrutura: ± Nome e classificação O nome de um padrão é um importante elemento, pois desejamos que seja adotado pelos desenvolvedores como uma referência que descreve um problema de projeto, sua solução, características e conseqüências. Não é uma tarefa fácil encontrar um nome representativo e ao mesmo tempo simples. A classificação é relacionada aos tipos de padrão, na visão do Go, e pode ser considerada opcional. ± Propósito Descrição sintética do propósito do padrão, o que ele faz, seu racional e que problema de projeto pretende solucionar. ± Nome secundário Se existir, quais são os outros nomes que poderiam identificar esse padrão. ± Motivação Descreve o problema e o contexto onde ocorre, de maneira mais detalhada, esquematizando como os elementos usados pelo padrão permitem solucionar o problema. ± Aplicabilidade Caracteriza as situações onde o padrão pode ser aplicado, possivelmente citando um caso de projeto problemático no qual o emprego desse padrão seria recomendado. É interessante relacionar como identificar essas situações de uso. 411 ± Estrutura Representação gráfica da estrutura das classes envolvidas no padrão utilizando uma notação padronizada 3. ± Participantes Especifica os elementos (classes e objetos) que compõem a solução e suas responsabilidades. Não descreve uma implementação particular, mas as idéias contidas na solução. ± Colaborações Descreve como os participantes do padrão se relacionam, ou seja, como desempenham seus papéis na estrutura da solução. ± Conseqüências Relaciona os resultados do emprego desse padrão, as vantagens e desvantagens, envolvendo questões como flexibilidade, portabilidade e outras. 3. Originalmente utilizava a notação OMT Object Modeling Technique (Rumbaugh et al., 1991). Hoje seria mais adequado o uso da UML Unified Modeling Language (Coad et al., 1999, Page-Jones, 2001). EDITORA FUTURA 06.pmd /12/02, 16:17

8 MAIS JAVA ± Implementação Relaciona técnicas úteis na implementação do padrão, assim como conselhos e avisos sobre problemas potenciais, bem como questões relacionadas ao uso de linguagens específicas. ± Exemplo Trechos de código em linguagens representativas (C++ ou Java) que demonstrem a implementação do padrão. ± Usos conhecidos Situações reais de uso do padrão. ± Padrões relacionados Padrões de projeto que fazem parte desse padrão ou poderiam (ou não) ser usados para solucionar o problema de projeto em análise. 6.5 Classificação dos padrões 412 Além dos padrões de projeto existem outros, cujo âmbito pode ser mais ou menos restrito, embora tal classificação seja um tema muito subjetivo. Alguns autores (Buschmann & Meunier, 1995; Coplien, 1996) organizam os padrões em uma hierarquia de três níveis, como ilustrado na igura 6.1, que são: ± Padrão de arquitetura (Architectural Patterns ou ramework Patterns) Oferecem um esquema de organização estrutural de sistemas que fornece um conjunto de subsistemas predefinidos, com responsabilidades específicas, incluindo regras para organizar os relacionamentos entre eles. Se preocupam com o sistema como um todo, ou seja, seus componentes e propriedades globais. Representam o nível mais alto dos padrões. ± Padrões de projeto (Design Patterns) Descrevem problemas que se repetem, o contexto específico de sua ocorrência e a solução em termos estruturais. Um padrão de projeto abstrai toda uma situação e sua solução, podendo ser considerado uma microarquitetura, cuja aplicação não afeta a estrutura global do sistema no qual se emprega. Também provê um esquema de refinamento tanto dos subsistemas e componentes do software, como dos relacionamentos entre eles. Representam o nível intermediário dos padrões. ± Idioma (Idioms) Um idioma é um padrão de projeto implementado em uma determinada linguagem de programação, que considera aspectos específicos dos seus componentes (classes e objetos) e de suas relações. Dado sua especificidade, é considerado um padrão de baixo nível. 06.pmd /12/02, 16:17

9 Capítulo 6: Padrões de projeto Figura 6.1 Níveis dos padrões de projeto. Os padrões de projeto, especificamente falando, poderiam ser divididos em três tipos ou categorias (Gamma et al., 1993, 1995) que indicam a natureza essencial dos padrões: ± Padrões de criação (creational patterns), relacionados com o processo de criação de objetos (instanciação). ± Padrões estruturais (structural patterns), que consideram formas de composição de classes ou objetos. ± Padrões de comportamento (behavior patterns), que tratam a maneira com que classes e objetos podem interagir. Essa divisão dos padrões objetiva apenas elucidar a característica principal da atuação de um certo padrão, se associando ao próprio padrão para compor um vocabulário para discussão e desenvolvimento de projetos de software Catálogo de padrões Nesta seção, apresentaremos um conjunto de padrões de projeto úteis, onde discutiremos o problema e a solução proposta, incluindo pequenas implementações que ilustram sua aplicação. Adotaremos uma variação resumida da forma Go. Também destacaremos onde esses padrões são empregados na API Java. Os padrões que serão tratados e seus respetivos tipos são: Criação Estruturais Comportamento Singleton (6.6.1) Composite (6.6.4) Iterator (6.6.2) Factory Method (6.6.3) Decorator (6.6.6) Command (6.6.5) AbstractFactory (6.6.9) Adapter (6.6.8) Strategy (6.6.7) Observer (6.6.10) EDITORA FUTURA 06.pmd /12/02, 16:17

10 MAIS JAVA Singleton Motivação, propósito e aplicabilidade É um padrão de projeto muito simples, que permite ilustrar muitas das características necessárias aos padrões de projeto, possui inúmeras aplicações e sua implementação é muito direta. Segundo a classificação Go, é um padrão de criação. A motivação para esse padrão vem do fato de que muitas aplicações necessitam garantir a existência de uma única instância de certas classes, pois tais objetos podem fazer uso de recursos cuja utilização deve ser exclusiva, ou porque desejamos que os demais elementos do sistema compartilhem de um único objeto particular. Tais situações surgem quando vários subsistemas utilizam um único arquivo de configuração, permitindo sua modificação concorrentemente. Outra situação possível é quando uma conexão com um banco de dados ou um sistema remoto só pode ser estabelecida de modo exclusivo, tendo de ser compartilhada por vários módulos existentes. Em sistemas dotados de múltiplas janelas de tipos distintos, é comum que algumas dessas janelas não necessitem ou não possam ser instanciadas inúmeras vezes. Como não queremos que os usuários dessas classes tenham que zelar por essa condição, ao mesmo tempo que desejamos prover acesso simples à única instância que poderá existir, adicionaremos essas responsabilidades às classes cujo comportamento será o de um Singleton. 414 Assim sendo, o padrão de projeto Singleton tem como propósito garantir que para uma classe específica só exista uma dada instância, a qual possa ser obtida de modo global e uniforme. Estrutura, participantes e conseqüências A estrutura do Singleton está ilustrada no diagrama de classes da igura 6.2. Figura 6.2 Estrutura do padrão Singleton. A implementação desse padrão de projeto solicita que a classe, para a qual só deve possuir uma instância, exiba as características da estrutura ilustrada, ou seja: ± Classe Singleton Efetua o armazenamento da única instância permitida; Implementa a operação getinstance(), a qual garante que apenas um objeto será criado, retornando tal instância. 06.pmd /12/02, 16:17

11 Capítulo 6: Padrões de projeto Instâncias das classes que implementam o padrão Singleton só poderão ser obtidas por meio da operação pública e estática getinstance() que retorna a instância única. Implementação e exemplo Uma implementação Java do padrão Singleton, como no Exemplo 6.1, deve utilizar-se de campo estático do tipo da própria classe para armazenar a referência da única instância permitida. Um método estático, também com tipo de retorno da própria classe, provê um ponto único de acesso a tal instância. Se a operação de instanciação ocorrer apenas na primeira solicitação de um objeto da classe, garantimos a instância única ao mesmo tempo que a operação de criação só ocorrerá quando for estritamente necessário (lazy instantiation). Como o Java suporta a clonagem de objetos (Sun, 2001A), devemos fazer tal classe final, ou seja, devemos impedir que essa classe seja utilizada como superclasse na criação de subclasses por meio da herança, pois se as subclasses implementarem a interface java.lang.cloneable, objetos assim obtidos poderão ser duplicados (por meio do método clone()), o que romperia com as obrigações desse padrão. Esse padrão pode ser modificado para permitir que um número maior de instâncias seja criado, limitados a um valor determinado, caracterizando um pool de objetos. Temos no Exemplo 6.1 um modelo de implementação Java de um Singleton com a classe SingletonImp. Esse exemplo não oferece outras funcionalidades a não ser aquelas descritas pelo padrão de projeto Singleton, mas servindo apenas como uma implementação de referência. Uma classe concreta que necessite ter apenas um único objeto instanciado pode adicionar os métodos e campos necessários à estrutura sugerida. 415 // SingletonImpl.java // classe declarada como final // impede seu uso através de herança public final class SingletonImpl { // campo estático armazena a única // instância desta classe private static SingletonImpl instance = null; // outros campos podem ser adicionados // construtores devem ser privados // para impedir uso externo private SingletonImpl() { // campos da classe podem ser // normalmente inicializados // retorna o único objeto que // pode ser instanciado public static SingletonImpl getinstance() { if (instance==null) { // instanciação ocorre apenas se um // objeto for solicitado mas só uma vez EDITORA FUTURA 06.pmd /12/02, 16:17

12 MAIS JAVA Exemplo 6.1 instance = new SingletonImpl(); return instance; Modelo para implementação de Singleton. Um outro exemplo de implementação do padrão Singleton é exibido no Exemplo 6.2, onde a classe SingleDBConn garante que apenas uma conexão será realizada com o banco de dados cuja URL é obtida de um arquivo de configuração (um arquivo de propriedades) denominado config.properties, garantindo que essa classe possa ser usada em diferentes situações sem necessidade de recompilação. Em vez de ser retornada uma instância do tipo SingleDBConn por meio de um método getinstance(), optamos por retornar a conexão única a ser realizada com o banco de dados indicado no arquivo de configuração por meio do método getconnection(). Se o arquivo de configuração não puder ser lido ou a conexão não puder ser realizada, será lançada uma exceção. // SingleDBConn.java // Singleton para conexão com BD import java.io.*; import java.sql.*; import java.util.*; 416 public final class SingleDBConn { // referência única private static SingleDBConn instance = null; // campo adicional private static Connection connection = null; // construtor privado private SingleDBConn() throws Exception { Properties prop = new Properties(); prop.load(new ileinputstream("config.properties")); String url = prop.getproperty("url"); connection = DriverManager.getConnection(url); // retorna conexão única public static Connection getconnection() throws Exception { if (instance==null) { // "lazy-instantiation" instance = new SingleDBConn(); return connection; Exemplo 6.2 Classe SingleDBConn. Aplicações que necessitem utilizar um banco de dados que exija uma única conexão podem fazer uso dessa classe que simplificará o controle de tal restrição. 06.pmd /12/02, 16:17

13 Capítulo 6: Padrões de projeto Usos conhecidos e padrões relacionados Toda máquina virtual possui uma única instância da classe java.lang.runtime, que permite que a aplicação corrente acesse o ambiente no qual está sendo executada (Sun, 2001A). Como a JVM efetivamente opera em um único ambiente, só pode existir uma instância dessa classe, obtida pelo método getruntime(). É claro que a classe Runtime implementa um padrão de projeto Singleton para cumprir com essa restrição. O padrão Singleton, como implementado aqui, não garante uma única instância para diferentes máquinas virtuais, isto é, se em um sistema estivermos usando várias máquinas virtuais concorrentemente, o padrão Singleton garantirá uma instância da classe controlada para cada JVM ativa. Esse padrão também pode ser utilizado para o controle de impressão (acesso controlado a uma certa fila de impressão), acesso restrito a portas de comunicação, uso de recursos restritos do sistema etc. Outros padrões de projeto podem ser construídos por meio do Singleton, tal como o Abstract actory (6.6.9) Iterator Motivação, propósito e aplicabilidade 417 É um outro padrão de projeto relativamente simples, considerado como um padrão de comportamento, muito útil para prover a navegação consistente entre elementos mantidos por uma coleção ou agregado de objetos, sem que sua estrutura se torne evidente ou que seja necessário conhecimento de sua representação interna. Stroustrup afirma que: iterators são a cola que mantêm containers e algoritmos juntos. [Tradução livre] (Stroustrup, 1997, p. 549) Existem inúmeras estruturas de dados que representam coleções, tais como arrays, listas ligadas, árvores etc. Da mesma forma, é freqüente a necessidade de percorrermos (ou navegarmos) os elementos armazenados por essas estruturas. Ao mesmo tempo, não é conveniente que o uso dessas estruturas nos obrigue a conhecer sua representação interna para possibilitar a navegação, nem que as interfaces dessas estruturas sejam oneradas com operações de alto nível para a realização dessa tarefa. Para desacoplarmos as estruturas de dados das formas de sua navegação, propõe-se o padrão de projeto Iterator, cujos objetos serão responsáveis por prover o serviço de navegação pelos elementos da coleção a que se referem, sem expor a representação interna dessas estruturas nem violar seu encapsulamento. EDITORA FUTURA 06.pmd /12/02, 16:17

14 MAIS JAVA Esse padrão pretende oferecer uma interface consistente para que os elementos de uma estrutura de dados possam ser adequadamente percorridos, ou seja, ele pode ser usado para prover o acesso ao conteúdo dessas estruturas sem violar seu encapsulamento e sem a necessidade de conhecimento da representação interna. Permite ainda que diferentes formas de navegação sejam implementadas e possibilita o controle de múltiplos percursos de navegação por uma mesma estrutura. Uma boa prática de programação Java, que está se tornando comum, é a denominação de interfaces com o prefixo I, seguido de um nome ou verbo representativo das habilidades especificadas pela interface (Coad et al., 1999, p. 83). Uma interface para coleções poderia ser chamada ICollection ou para o padrão Iterator poderia ser denominada IIterator. Em particular, esses nomes evitam criar confusão com os adotados pelo framework de coleções (java.util.collection e java.util.iterator) visto no Capítulo 1. Estrutura, participantes e conseqüências Na igura 6.3, temos um diagrama de classes que ilustra a estrutura desse padrão. 418 Figura 6.3 Estrutura do padrão Iterator. Existem quatro participantes nessa estrutura: ± Interface ICollection Especifica a operação responsável por retornar um objeto IIterator (getiterator()), o qual possibilitará realizar a navegação entre os elementos de implementações concretas das coleções (ICollection). Pode especificar métodos adicionais às implementações de coleções. 06.pmd /12/02, 16:17

15 Capítulo 6: Padrões de projeto ± Interface IIterator Especifica as operações genéricas que permitirão realizar a navegação entre os elementos de uma coleção de objetos, no caso hasnext() (que verifica a existência de um próximo elemento) e next() (que retorna o próximo elemento existente). ± Classe CollectionImpl Implementação da interface ICollection que mantém um conjunto ou coleção de objetos em uma representação interna particular, que não precisa ser conhecida por seus usuários. Por meio do método getiterator(), cria e retorna um objeto IteratorImpl apropriado, capaz de realizar a navegação entre seus elementos. ± Classe IteratorImpl Implementação da interface IIterator que oferece as operações nela definidas. Conhece a representação interna dos objetos CollectionImpl, permitindo uma forma consistente de navegação que oculta tal representação. Efetivamente a classe IteratorImpl provê o serviço de navegação do conteúdo da estrutura de CollectionImpl, enquanto ICollection e IIterator definem as interfaces que devem ser implementadas pelas classes concretas, possibilitando também tratamento polimórfico. A aplicação desse padrão apresenta várias conseqüências benéficas: ± Diferentes estruturas de dados podem utilizar-se das mesmas interfaces providas por ICollection e IIterator para oferecer um serviço de navegação, cuja semântica é consistente. 419 ± icam claramente separadas as responsabilidades de armazenamento e navegação de uma estrutura de dados particular, simplificando tanto as implementações concretas de ICollection (armazenamento) como de IIterator (navegação). ± Cada objeto do tipo IIterator pode manter um percurso de navegação independente para uma mesma coleção. ± É possível implementarmos diferentes estratégias de navegação para uma mesma coleção (navegação em sentido reverso, bidirecional, ordenada etc.). Implementação e exemplo A implementação de uma interface IIterator define as operações gerais que devem estar disponíveis nos objetos destinados a permitir a navegação pelos elementos de coleções e pode ser feita como é exibida no Exemplo 6.3. Identificamos no código a declaração do método hasnext(), que deve indicar a existência de um próximo elemento na coleção, e next(), que deve retornar o próximo elemento disponível. EDITORA FUTURA 06.pmd /12/02, 16:17

16 MAIS JAVA // IIterator.java // interface para navegação de coleções quaisquer public interface IIterator { // verifica a existência de um próximo elemento public boolean hasnext(); // retorna o próximo elemento public Object next(); Exemplo 6.3 Interface Iiterator. Neste padrão de projeto, as coleções devem ser dotadas de uma interface que minimamente inclua a operação que possibilita o retorno de objetos IIterator. Operações adicionais, como adição e remoção de elementos, poderiam ser também definidas, como no Exemplo 6.4, que mostra a interface ICollection. // ICollection.java 420 // interface para obtenção de Iterator para coleções public interface ICollection { // obtenção de um Iterator public IIterator getiterator(); // determina existência de um elemento public boolean has(object object); // adição de um elemento public boolean add(object object); // remoção de um elemento public boolean remove(object object); // remoção de todos os elementos public void removeall(); Exemplo 6.4 Interface Icollection. As coleções, isto é, as estruturas de dados que conterão diversos elementos que adotarão a interface ICollection, devem prover uma implementação adequada para cada um dos métodos especificados, em particular para a operação getiterator(), que retornará um objeto que implementa a interface IIterator e que é capaz de permitir a navegação pelos elementos contidos por tal coleção. A classe ConjuntoLimitado, exibida no Exemplo 6.5, define uma estrutura de dados que pode armazenar um conjunto de objetos não nulos, limitado a um número predeterminado de elementos. A implementação dessa classe se baseia no uso de um array, cujo número de elementos é determinado na instanciação do objeto por meio de um dos dois construtores existentes. A estrutura ConjuntoLimitado implementa as operações de adição, pesquisa e remoção de elementos exigidas pela interface, mas isso não evidencia como internamente ocorre o armazenamento dos elementos. A operação getiterator() retorna um objeto IIterator específico, na verdade uma implementação concreta da interface IIterator denominada ConjuntoLimitadoIterator. Como proposto pelo padrão Iterator, a classe ConjuntoLimitado tem como responsabilidade a organização dos elementos, enquanto a classe ConjuntoLimitadoIterator tem como atribuição permitir a navegação pelos elementos contidos nos objetos ConjuntoLimitado. 06.pmd /12/02, 16:17

17 Capítulo 6: Padrões de projeto // ConjuntoLimitado.java public class ConjuntoLimitado implements ICollection { // arrays para armazenamento do conteúdo do conjunto Object content[]; // construtor default public ConjuntoLimitado() { this(10); // construtor parametrizado public ConjuntoLimitado(int size) { content = new Object[size]; // determina posição de elemento no conjunto private int indexof(object object) { for(int pos=0; pos<content.length; pos++) { if (content[pos]!=null) { if (content[pos].equals(object)) { return pos; return -1; // verifica a existência de elemento no conjunto public boolean has(object object) { return indexof(object)!=-1; 421 // adição de novo elemento no conjunto public boolean add(object object) { if (object!=null) { for(int pos=0; pos<content.length; pos++) { if (content[pos]==null) { content[pos] = object; return true; return false; // remove elemento do conjunto public boolean remove(object object) { int pos = indexof(object); if (pos!= -1) { content[pos] = null; return true; return false; // remove todos os elementos do conjunto EDITORA FUTURA 06.pmd /12/02, 16:17

18 MAIS JAVA public void removeall() { for(int i=0; i<content.length; i++) { content[i] = null; // retorna Iterator específico do conjunto public IIterator getiterator() { return new ConjuntoLimitadoIterator(this); Exemplo 6.5 Classe ConjuntoLimitado. A classe ConjuntoLimitadoIterator, que foi definida separadamente, como mostra o Exemplo 6.6, implementa a interface IIterator e armazena a referência do objeto ConjuntoLimitado que lhe deu origem, permitindo assim acessar os elementos contidos nessa coleção para prover o serviço de navegação desejado. Notem que o campo inteiro last mantém o controle de posição da navegação, de forma que cada objeto ConjuntoLimitadoIterator possa tratar os percursos independentes. // Iterator específico de ConjuntoLimitado public class ConjuntoLimitadoIterator implements IIterator { private ConjuntoLimitado conjunto; // referência para conjunto private int last; // controle de posição 422 // construtor parametrizado public ConjuntoLimitadoIterator(ConjuntoLimitado conjunto) { this.conjunto = conjunto; last = -1; // verifica a existência de um próximo elemento public boolean hasnext() { for(int pos=last+1; pos<conjunto.content.length; pos++) { if (conjunto.content[pos]!=null) { return true; return false; // retorna o próximo elemento public Object next() { for(int pos=last+1; pos<conjunto.content.length; pos++) { if (conjunto.content[pos]!=null) { last = pos; return conjunto.content[pos]; return null; Exemplo 6.6 Classe ConjuntoLimitadoIterator. 06.pmd /12/02, 16:17

19 Capítulo 6: Padrões de projeto O pequeno programa a seguir (Exemplo 6.7) cria um objeto ConjuntoLimitado, adiciona e remove alguns elementos por meio dos métodos da interface ICollection e utiliza um objeto IIterator para percorrer e exibir seu conteúdo. // TestaConjunto.java public class TestaConjunto { public static void main(string a[]) { // instancia coleção ICollection conjunto = new ConjuntoLimitado(); System.out.println("Adicionando objetos ao Conjunto..."); for(int i=0; i<6; i++) { conjunto.add("objeto#"+i); mostraconjunto(conjunto); System.out.println("Removendo objetos do Conjunto..."); for(int i=0; i<6; i+=2) { conjunto.remove("objeto#"+i); mostraconjunto(conjunto); System.out.println("Adicao extra..."); conjunto.add("objeto#100"); mostraconjunto(conjunto); public static void mostraconjunto(icollection conjunto) { System.out.println("Conteudo:"); IIterator ii = conjunto.getiterator(); while(ii.hasnext()) { System.out.print(ii.next()+" "); System.out.println("\n"); Exemplo 6.7 Classe TestaConjunto. 423 Executando este programa, teríamos: >java TestaConjunto Adicionando objetos ao Conjunto... Conteudo: Objeto#0 Objeto#1 Objeto#2 Objeto#3 Objeto#4 Objeto#5 Removendo objetos do Conjunto... Conteudo: Objeto#1 Objeto#3 Objeto#5 Adicao extra... Conteudo: Objeto#100 Objeto#1 Objeto#3 Objeto#5 EDITORA FUTURA 06.pmd 423

20 MAIS JAVA Devemos ressaltar que, para possibilitar que a classe ConjuntoLimitadoIterator tivesse acesso ao conteúdo dos objetos ConjuntoLimitado, o array interno destinado ao armazenamento do conteúdo foi implicitamente declarado com acesso package. Se tal campo fosse declarado como private, não seria possível o acesso necessário por parte da classe ConjuntoLimitadoIterator, e se fosse declarado como public, violaríamos seu encapsulamento, pois quaisquer classes teriam acesso direto ao array destinado a seu conteúdo. Mas o problema não foi resolvido, pois classes existentes no mesmo pacote também têm acesso a esse array. A solução desse problema vem com o uso das classes internas (inner classes). Se a classe que implementará a interface IIterator for interna, a mesma tem acesso às estruturas internas da classe ConjuntoLimitado (a classe externa ou outter class) mesmo que o array destinado a conteúdo seja declarado com acesso privado, garantindo seu encapsulamento. Isso acontece porque toda instância de uma classe interna (inner class) possui uma referência implícita para a instância da classe externa (outter class) que a originou. Para preservarmos a implementação anterior das classes ConjuntoLimitado e ConjuntoLimitadoIterator, criaremos uma classe ConjuntoLimitado2, com a mesma funcionalidade de ConjuntoLimitado, com uma classe interna IIteratorImpl, que implementa a interface IIterator. A classe interna é declarada privada para que suas instâncias só possam ser obtidas por meio da operação getiterator() da classe externa. Como o construtor parametrizado que existia anteriormente não mais receberá uma referência da coleção, o mesmo passa a ser default (sem parâmetros). Modificando-se a inicialização do campo last, podemos eliminar tal construtor, simplificando a implementação do IIterator. 424 // ConjuntoLimitado2.java public class ConjuntoLimitado2 implements ICollection { // arrays para armazenamento do conteúdo do conjunto private Object content[]; // construtor default public ConjuntoLimitado2() { this(10); // construtor parametrizado public ConjuntoLimitado2(int size) { content = new Object[size]; // determina posição de elemento no conjunto private int indexof(object object) { for(int pos=0; pos<content.length; pos++) { if (content[pos]!=null) { if (content[pos].equals(object)) { return pos; return -1; // verifica a existência de elemento no conjunto public boolean has(object object) { 06.pmd 424

21 Capítulo 6: Padrões de projeto return indexof(object)!=-1; // adição de novo elemento no conjunto public boolean add(object object) { if (object!=null) { for(int pos=0; pos<content.length; pos++) { if (content[pos]==null) { content[pos] = object; return true; return false; // remove elemento do conjunto public boolean remove(object object) { int pos = indexof(object); if (pos!= -1) { content[pos] = null; return true; return false; // remove todos os elementos do conjunto public void removeall() { for(int i=0; i<content.length; i++) { content[i] = null; 425 // retorna Iterator específico do conjunto public IIterator getiterator() { return new IIteratorImpl(); // Iterator específico de ConjuntoLimitado private class IIteratorImpl implements IIterator { private int last = -1; // controle de posição // verifica a existência de um próximo elemento public boolean hasnext() { for(int pos=last+1; pos<content.length; pos++) { if (content[pos]!=null) { return true; return false; // retorna o próximo elemento public Object next() { for(int pos=last+1; pos<content.length; pos++) { if (content[pos]!=null) { last = pos; EDITORA FUTURA 06.pmd 425

22 MAIS JAVA Exemplo 6.8 return content[pos]; return null; Classe ConjuntoLimitado2. O uso da classe Conjunto2 é idêntico ao da classe Conjunto, com a vantagem adicional do encapsulamento melhorado de sua estrutura interna. No diretório de exemplos do Capítulo 6, temos o programa ConjuntoDemo, uma aplicação Swing, que permite demonstrar interativamente as capacidades da coleção ConjuntoLimitado2. Usos conhecidos e padrões relacionados 426 O framework de coleções (mostrado no Capítulo 1) faz uso intensivo desse padrão: a interface java.util.collection, raiz desse framework, especifica a operação iterator() que retorna um objeto que implementa a interface java.util.iterator (Sun, 2001A). Sendo assim, as principais interfaces derivadas de Collection, que são Set e List, também exigem essa operação, assim como as classes abstratas AbstractCollection, AbstractSet e AbstractList. Cada implementação concreta fornece por meio da operação iterator() um objeto que implementa a interface Iterator e que é especializado na navegação pelos elementos dessa coleção. Tais objetos Iterator retornados são usualmente capazes de realizar algumas operações adicionais, tais como remoção ou modificação de elementos da coleção. Nas versões do Java (anteriores à introdução do framework de coleções), a interface java.util.enumeration era utilizada pelos objetos atualmente implementados como Iterator. As classes java.util.stringtokenizer e java.util.vectorri: ainda utilizam objetos Enumeration. Ainda dentro da API Java, temos a interface java.sql.resultset, pertencente ao JDBC Java DataBase Connectivity, que oferece um sofisticado suporte à navegação de resultados retornados pela execução de consultas em bancos de dados. A STL Standard Template Library da linguagem C++ também utiliza o conceito de containers, semelhante ao de coleção, cujos objetos contidos podem ser percorridos por meio do objetos Iterator, separando a implementação de tais estruturas das responsabilidades de navegação por seus elementos (Stroustrup, 1997, p. 549). Outros padrões que podem ser relacionados ao Iterator são: Decorator (6.6.6) e actory Method (6.6.3) ou Memento. (Gamma et al., 1995, p. 283) 06.pmd 426

23 Capítulo 6: Padrões de projeto Factory Method Motivação, propósito e aplicabilidade Uma estratégia comum no desenvolvimento de sistemas é utilizar uma determinada classe como base para a criação de várias outras subclasses mais especializadas. A base dessa hierarquia tornase uma interface comum para os tipos derivados, intenção que pode ser reforçada tornando-a uma classe abstrata ou uma interface. A adição de novos tipos pode seguir o mesmo processo, sem que seja afetado o código existente. Mas existe um problema na criação de objetos dessa hierarquia, pois nos pontos onde um objeto desse tipo é criado, como antecipar a adição de novos tipos, isto é, como selecionar uma dentre as classes disponíveis se, possivelmente, novas implementações são incorporadas ao sistema? O padrão actory Method (que pode ser conhecido como método fábrica) trata exatamente dessa questão, definindo uma interface para criação de objetos, agora entendidos como produtos, deixando que uma classe especial (a fábrica ) decida qual classe será utilizada na instanciação de objetos, isolando o ponto onde se requisitam novos objetos daquele onde ocorre a seleção dos tipos existentes para sua criação. Assim, na implementação dessa classe especial fábrica, deverá existir um método responsável pela fabricação dos produtos, o método fábrica, que cria objetos pertencentes a uma família de classes, sendo assim um padrão de criação. Essa solução é aplicável quando existem classes que não podem prever a disponibilidade de novos tipos para a criação de objetos; quando o uso desses objetos se dá por meio de uma interface comum, importando assim como ocorre a criação dos mesmos; e é desejável que disponhamos de classes especiais que possam decidir pelo tipo de objeto a ser criado. 427 Estrutura, participantes e conseqüências Podemos notar a existência de quatro componentes distintos na estrutura desse padrão (ilustrada na igura 6.4), que são descritos a seguir. ± Interface IProduct Especifica a interface comum para os tipos especializados que deverão ser instanciados. ± Classe(s) ProductImpl Uma ou mais classes concretas que implementa a interface IProduct, dotando seus objetos de comportamento e características especializadas. ± Interface I actory Especifica a interface para obtenção de objetos que implementam a interface IProduct, por exemplo uma operação createproduct() (o método fábrica) que retorna objetos de tal tipo. EDITORA FUTURA 06.pmd 427

24 MAIS JAVA ± Classe actoryimpl Classe concreta que implementa a interface de obtenção de objetos que por sua vez implementam a interface IProduct, ou seja, a operação createproduct(); A operação criaproduto() é responsável por selecionar qual classe concreta será utilizada para a criação de um objeto IProduct. 428 Figura 6.4 Estrutura do padrão Factory Method. Uma conseqüência direta do uso desse padrão é a dissociação entre a aplicação e as classes específicas, concentrando no método fábrica tal conhecimento. Neste sentido, a classe actoryimpl pode ser utilizada pela aplicação propriamente dita, que por meio dos métodos fábrica obtém objetos desejados. Outra conseqüência é que a adição de novas subclasses de produto exigirá apenas a modificação do método fábrica, tornando o código mais robusto. Implementação e exemplo O padrão actory Method, como vimos, exige que tenhamos duas interfaces para definição do acesso aos participantes IProduct e I actory, relativas aos seus produtos e às fábricas. Imaginando que os produtos desejados são coleções, poderíamos tomar a interface ICollection (Exemplo 6.4) como equivalente à interface IProduct da estrutura desse padrão. Todos os produtos que serão fornecidos pelo actory Method devem assim implementar a interface ICollection, tal como a classe ConjuntoLimitado2, dada no Exemplo 6.8, que possui todas as operações indicadas por ICollection. Analogamente, poderíamos implementar outra classe de 06.pmd 428

25 Capítulo 6: Padrões de projeto produto, tal como ConjuntoNaoLimitado, destinada a oferecer um conjunto com número máximo de elementos variável, como ilustrado no Exemplo 6.9. Essa nova implementação é baseada em uma lista ligada simples em vez de um array. // ConjuntoNaoLimitado.java public class ConjuntoNaoLimitado implements ICollection { // arrays para armazenamento do conteúdo do conjunto private Node start = null; // verifica a existência de elemento no conjunto public boolean has(object object) { Node element = start; while (element!=null) { if (element.content.equals(object)) { return true; element = element.next; return false; // adição de novo elemento no conjunto public boolean add(object object) { if (object!=null) { start = new Node(object, start); return true; return false; 429 // remove elemento do conjunto public boolean remove(object object) { if (start!=null) { if (start.content.equals(object)) { Node todelete = start; start = start.next; todelete = null; return true; else { Node last = start; while (last.next!=null) { if (last.next.content.equals(object)) { Node todelete = last.next; last.next = last.next.next; todelete = null; return true; last = last.next; return false; // remove todos os elementos do conjunto EDITORA FUTURA 06.pmd 429

26 MAIS JAVA public void removeall() { while (start!=null) { Node todelete = start; start = start.next; todelete = null; // retorna Iterator específico do conjunto public IIterator getiterator() { return new IIteratorImpl(); // Nó para lista ligada de elementos do ConjuntoNaoLimitado private class Node { public Object content; public Node next; public Node(Object content, Node next) { this.content = content; this.next = next; // Iterator específico de ConjuntoNaoLimitado private class IIteratorImpl implements IIterator { private Node next = start; // controle de posição 430 // verifica a existência de um próximo elemento public boolean hasnext() { return next!=null; Exemplo 6.9 // retorna o próximo elemento public Object next() { if (hasnext()) { Object tmp = next.content; next = next.next; return tmp; return null; Classe ConjuntoNaoLimitado. Para evitarmos que as aplicações tenham que especificar diretamente as classes concretas que implementam a interface ICollection, no caso ConjuntoLimitado2 e ConjuntoNaoLimitado, a criação de objetos produto se fará por meio de classes que deverão implementar a outra interface necessária a esse padrão, denominada por exemplo ICollection actory, a qual especifica o método que fabricará tais objetos. Essa interface está relacionada no Exemplo 6.10, onde podemos notar que createcollection(string) é o método fábrica, o qual recebe um objeto String indicativo do produto desejado (a coleção). Se o objeto fornecido não indicar um produto disponível (uma implementação conhecida de ICollection), será lançada a exceção de execução 06.pmd 430

27 Capítulo 6: Padrões de projeto CollectionNotAvailableException, criada com o propósito exclusivo de sinalizar essa situação (veja o Exemplo 6.11). // ICollection actory.java public interface ICollection actory { // retorna "produtos" disponíveis public String[] getavailablecollections(); // cria um "produto" conforme tipo dado public ICollection createcollection(string collectionname) throws CollectionNotAvailableException; Exemplo 6.10 Interface IcollectionFactory. // CollectionNotAvailableException.java public class CollectionNotAvailableException extends RuntimeException { public CollectionNotAvailableException(String message) { super(message); Exemplo 6.11 Classe CollectionNotAvailableException. Ainda na interface ICollection actory adicionamos um outro método, denominado getavailablecollections(), que permite retornar um array de objetos String válidos para seleção das coleções. Dessa maneira, é possível que as aplicações que necessitem utilizar coleções distintas possam determinar quais tipos estão disponíveis ou serem configuradas diferentemente sem efetivo conhecimento das classes envolvidas. 431 A exceção CollectionNotAvailableException possui apenas um construtor parametrizado com a mensagem de erro, que aciona o construtor equivalente de sua superclasse java.lang.runtimeexception. Notemos que, sendo uma exceção de execução, seu tratamento não é obrigatório o que simplifica seu uso. Uma implementação possível da interface ICollection actory é dada no Exemplo Um array de objetos String, com a identificação dos tipos de coleções disponíveis (tais strings são livres, ou seja, não precisam ter relação com o nome das classes concretas associadas). O método getavailablecollections() retorna uma referência para esse array, o qual é declarado final para que seus objetos não possam ser alterados por meio da referência retornada. O método createcollection(string), mediante o recebimento de uma identificação válida, instancia o objeto usando a classe concreta adequada; caso contrário, lança a exceção CollectionNotAvailableException. // Collection actoryimpl.java public class Collection actoryimpl implements ICollection actory { // tipos disponíveis private final String types[] = { "ConjuntoLimitado", "ConjuntoNaoLimitado" ; // retorna "produtos" disponíveis public String[] getavailablecollections() { EDITORA FUTURA 06.pmd 431

28 MAIS JAVA return types; // cria um "produto" conforme tipo dado public ICollection createcollection(string collectionname) throws CollectionNotAvailableException { if (collectionname.equals(types[0])) return new ConjuntoLimitado2(); if (collectionname.equals(types[1])) return new ConjuntoNaoLimitado(); throw new CollectionNotAvailableException(collectionName); Exemplo 6.12 Classe CollectionFactoryImpl. A aplicação TestaConjunto, dada no Exemplo 6.7, opera uma coleção exclusivamente por meio da interface ICollection, embora na instanciação da coleção utilize diretamente o nome da classe de uma das implementações concretas dessa interface, no caso ConjuntoLimitado, conforme o trecho destacado: // instancia coleção ICollection conjunto = new ConjuntoLimitado(); 432 Se quiséssemos que essa aplicação utilizasse outra implementação, por exemplo ConjuntoLimitado2, a mesma deveria ser modificada. No caso temos uma modificação muito simples, localizada em uma única linha, mas se ocorresse em um sistema de maior porte, todas as operações de instanciação de tal coleção deveriam ser localizadas e modificadas, o que obviamente é um trabalho mais complexo e também sujeito a erros (alguns pontos poderiam ser esquecidos). Utilizando uma implementação de uma fábrica de coleções (Exemplo 6.12), tal código seria substituído por: // instancia fábrica de coleções ICollection actory fabrica = new Collection actoryimpl(); // obtém coleção ICollection conjunto = fabrica.createcollection("conjuntolimitado"); Com esse trecho de código, a aplicação TestaConjunto não teria que ser modificada quando substituíssemos a classe ConjuntoLimitado por ConjuntoLimitado2. Apenas a implementação da fábrica (Collection actoryimpl) deveria ser modificada em um único ponto. Se para TestaConjunto parece que apenas deslocamos o local da alteração dessa classe para a implementação da fábrica, se novamente considerarmos um sistema complexo, todas as modificações decorrentes do uso direto de classes concretas seriam reduzidas a uma modificação simples na implementação da 06.pmd 432

29 Capítulo 6: Padrões de projeto fábrica, evidenciando a enorme utilidade do padrão actory Method no desacoplamento da necessidade de criação de objetos em relação às classes efetivamente usadas em sua instanciação. Por questões de simplicidade e conveniência, é comum que se dispense a implementação da interface IFactory na construção da classe fábrica (no caso CollectionFactoryImpl). Para tanto, são definidos apenas os métodos estáticos para criação de produtos, eliminando a necessidade de instanciarmos um objeto fábrica para que seus métodos possam ser usados. É importante notarmos que, embora simplifique o uso do padrão Factory Method, essa forma passa a não mais contar com uma interface comum a outras fábricas. Uma implementação alternativa da fábrica com apenas métodos estáticos para obtenção de produtos poderia ser como segue: // Collection actoryimpl2.java public class Collection actoryimpl2 { // cria ConjuntoLimitado public static ICollection createconjuntolimitado(int tam) { return new ConjuntoLimitado2(tam); // cria ConjuntoNaoLimitado public static ICollection createconjuntonaolimitado() { return new ConjuntoNaoLimitado(); Exemplo 6.13 Classe CollectionFactoryImpl O uso dessa nova fábrica seria como nos trechos dados abaixo: // obtenção de conjunto limitado ICollection conj1 = Collection actoryimpl2.createconjuntolimitado(2); // obtenção de conjunto não limitado ICollection conj2 = Collection actoryimpl2.createconjuntonaolimitado(); Usos conhecidos e padrões relacionados Na API do Java existem vários exemplos de aplicação desse padrão. No Swing, os componentes podem receber bordas (aplicação do padrão Decorator), as quais podem ser obtidas por meio do uso dos vários métodos fábrica estáticos existentes na classe javax.swing.border actory, sem que o usuário tenha que conhecer quais classes concretas foram especificamente utilizadas, manipulando-as conforme a interface javax.swing.border.border. As classes Socket e ServerSocket, do pacote java.net, têm suas instâncias obtidas através de fábricas, cuja interface é dada por SocketImpl actory (Sun, 2001A). EDITORA FUTURA 06.pmd 433

30 MAIS JAVA Um padrão intimamente ligado ao actory Method é o Abstract actory (6.6.9), ambos muito utilizados em frameworks e toolkits (Gamma et al., 1995, p. 115) Composite Motivação, propósito e aplicabilidade Em inúmeras situações, é necessário lidarmos com conjuntos de elementos agregados sob a forma de composições, por exemplo: peças que agrupadas formam conjuntos simples, que agregados a outros conjuntos e peças podem formar conjuntos mais sofisticados, e assim por diante, em uma estrutura que não é uma simples coleção de elementos, mas uma hierarquia particular de coleções de elementos, tal como em uma máquina qualquer (automóvel ou relógio de parede). Outra característica importante é que as composições podem ser tratadas como um único elemento, facilitando sua manipulação. Essas situações também ocorrem com freqüência no desenvolvimento de software: como sistemas gráficos, onde elementos simples, (retângulos, elipses, linhas e texto) podem ser agrupados formando figuras mais complexas, e estas podem compor desenhos; ou interfaces gráficas, onde componentes especiais (compartimentos ou contêiners) podem conter outros componentes, até mesmo outros contêiners, de forma a termos painéis, janelas ou diálogos. 434 As composições são o que chamamos de padrão de projeto Composite. Segundo Gamma et al. (1995, p. 163), esse padrão de estrutura compõe objetos estruturados como árvore para representar hierarquias elemento/conjunto. Podem, portanto, ser empregadas nas situações onde necessitamos representar hierarquias de conjuntos de objetos, de forma que possam ser ignoradas as diferenças entre a composição em si e os componentes individuais, facilitando e uniformizando seu tratamento. Estrutura, participantes e conseqüências Este padrão conta com quatro participantes: ± Classe Abstrata Component Especifica o comportamento esperado por todos os componentes presentes na hierarquia. Especifica a operação getparent() para determinação do componente pai (aquele que contém o componente filho). Pode especificar ou implementar outras operações comuns à hierarquia. ± Classe ContainerImpl Especifica e implementa as operações necessárias para os componentes que conterão outros componentes (os contêiners);. Armazena os componentes contidos. Implementa as operações especificadas para os componentes comuns em termos de sua execução para todos os componentes contidos. Pode substituir a implementação das operações comuns. 06.pmd 434

31 Capítulo 6: Padrões de projeto ± Classe ComponentImpl Implementa as operações necessárias para os componentes comuns (aqueles que não podem conter outros componentes). ± Classe Client Constrói composições de componentes por meio das operações gerais, definidas para todos os componentes, ou das específicas dos containers, destinadas ao agrupamento de componentes. Os quatro participantes do padrão Composite estão representados na estrutura ilustrada na igura 6.5, que é uma variação da versão clássica proposta por Gamma et al. (1995, p. 164). 435 Figura 6.5 Estrutura do padrão Composite. A estrutura clássica indica que as operações de adição, remoção e controle de componentes na composição são especificadas na classe abstrata Component, e assim disponíveis tanto nas folhas (classe ComponentImpl) como nas composições (classe ContainerImpl). Isso exige que providências especiais sejam tomadas quando tentamos inadvertidamente usar tais operações em componentes que não têm essa capacidade, provavelmente lançando mensagens de erro. Desta forma o Client pode construir hierarquias de componentes, manipulando-as genericamente como unidades, sem se preocupar com o fato de estar lidando com um ContainerImpl ou com um ComponentImpl, o que simplifica o código. Além disso, é possível que novos componentes sejam adicionados à hierarquia, podendo ser tratados da mesma forma e sem exigir modificações no Client. Apenas para execução das operações de controle de componentes é que será necessária a EDITORA FUTURA 06.pmd 435

32 MAIS JAVA distinção entre ContainerImpl e ComponentImpl (Geary, 2002), o que pode ser feito com o uso do operador instanceof: if (componente instanceof ContainerImpl) { // operações relativas a um compartimento else { // operações relativas a componentes comuns Implementação e exemplo 436 A criação de interfaces gráficas com componentes AWT ou Swing são ótimos exemplos de aplicação do padrão Composite. Tomando a família Swing (Sun, 2001A; Jandl, 2002, p. 294), podemos identificar claramente a correspondência de suas classes com os participantes do padrão Composite. A classe abstrata javax.swing.jcomponent dá origem a hierarquia de componentes do Swing e corresponde ao participante Component. Como a classe JComponent é derivada de java.awt.container, as habilidades relativas à administração de componentes já estão disponíveis. Assim, a partir da classe JComponent, existem implementações concretas de containers Swing, tal como a classe javax.swing.jpanel, que fornece uma área retangular (painel) que pode conter outros componentes, ou seja, corresponde ao participante ContainerImpl. As classes que fornecem os elementos da interface gráfica (JLabel rótulos, JButton botões, JText ield caixas de texto, JList caixas de lista, JMenuItem itens de menu etc.) são as implementações do participante ComponentImpl. Qualquer componente Swing pode ser adicionado a um container, inclusive um outro container para a construção de interfaces gráficas das aplicações, exceto janelas e diálogos (classes JWindow, J rame e JDialog) que não são derivadas de java.swing.jcomponent, mas sim de java.awt.window (janela básica da AWT). O uso da AWT se dá de forma semelhante. Observando a API Swing ou AWT, notamos que para os containers são definidas operações de adição e remoção de componentes, operações de contagem e obtenção individual de componentes, bem como outras operações particulares, tal como sugerido pelo padrão Composite. As implementações concretas dos diversos componentes oferecem os métodos definidos pela classe Jcomponent, além de adicionarem outros mais apropriados às suas características individuais. O Exemplo 6.14 mostra a construção de uma aplicação Swing simples, sem nenhuma funcionalidade, onde organizamos diversos componentes diferentes em camadas, separando-os em containers distintos. // CompositeDemo.java import java.awt.*; import java.awt.event.*; import javax.swing.*; public class CompositeDemo extends J rame { public CompositeDemo() { super("compositedemo"); // painel de conteúdo = container 0 JPanel p0 = new JPanel(new BorderLayout(5, 5)); p0.setborder(border actory.createtitledborder("container #0")); 06.pmd 436

33 Capítulo 6: Padrões de projeto p0.setbackground(color.blue); setcontentpane(p0); // painel 1 = container 1 JPanel p1 = new JPanel(new GridLayout(2, 1)); p1.setborder(border actory.createtitledborder("container #1")); p1.setbackground(color.orange); p1.add(new JLabel("JLabel #1")); p1.add(new JText ield("jtext ield #1")); // painel 2 = container 2 JPanel p2 = new JPanel(new GridLayout(2, 1)); p2.setborder(border actory.createtitledborder("container #2")); p2.add(new JCheckBox("JCheckBox #1")); p2.add(new JCheckBox("JCheckBox #2")); // painel 3 = container 3 JPanel p3 = new JPanel(new GridLayout(2, 1, 5, 5)); p3.setbackground(color.green); p3.setborder(border actory.createtitledborder("container #3")); p3.add(p1); p3.add(p2); getcontentpane().add("east", p3); // painel 4 = container 4 JPanel p4 = new JPanel(); p4.setborder(border actory.createtitledborder("container #4")); p4.setbackground(color.yellow); for(int i=1; i<=3; i++) { p4.add(new JButton("JButton #"+i)); getcontentpane().add("north", p4); // painel 5 = container 5 JPanel p5 = new JPanel(); p5.setborder(border actory.createtitledborder("container #5")); p5.setbackground(color.red); p5.add(new JLabel("JLabel #2")); getcontentpane().add("south", p5); // scrollpane = container 6 JScrollPane sp = new JScrollPane(new JTextArea("JTextArea #1")); sp.setborder(border actory.createtitledborder("container #6")); getcontentpane().add("center", sp); // outros ajustes setdefaultcloseoperation(j rame.exit_on_close); pack(); 437 public static void main(string a[]) { new CompositeDemo().show(); Exemplo 6.14 Classe CompositeDemo. Executando a aplicação, notamos que os diferentes containers são facilmente identificados devido a borda com título e o seu colorido. Na igura 6.6 temos uma ilustração da aplicação em operação e também sua decomposição em termos dos containers e componentes utilizados. EDITORA FUTURA 06.pmd 437

34 MAIS JAVA 438 Figura 6.6 Aplicação CompositeDemo e sua estrutura de containers. Usos conhecidos e padrões relacionados Como vimos, um grande exemplo de uso desse padrão é na construção de interfaces gráficas, como feito pela API Java nas famílias de componentes AWT ou Swing, e pela VCL Visual Component Library do Borland Delphi, ou pelo COM Component Object Model usado pela Microsoft nas interfaces de seus sistemas operacionais. O Composite pode ser utilizado em conjunto com outros padrões de projeto, tais como Chain of Responsability (Gamma, 1995, p. 223), Command (6.6.5) ou Decorator (6.6.6). Já o padrão Iterator pode ser utilizado para navegar pelos elementos de uma composição. Infelizmente as API AWT e Swing não utilizam a estratégia de oferecer objetos iterator para realizar a navegação pelos componentes existentes em um container, exigindo algum conhecimento específico de como realizar essa tarefa. 06.pmd 438

35 Capítulo 6: Padrões de projeto Command Motivação, propósito e aplicabilidade O padrão de projeto Command tem como propósito associar um comando a um objeto por meio de uma interface conhecida. Isso permite que as ações associadas aos objetos assim implementados possam ser realizadas transparentemente, sem necessidade de determinar o tipo do objeto ou mesmo conhecer a natureza da ação. Interfaces gráficas, a despeito da plataforma onde operam, são compostas de múltiplos componentes e orientadas a eventos, ou seja, quando tais componentes são acionados devem ser disparadas a execução de rotinas predeterminadas. Usualmente devemos determinar o tipo de componente que foi acionado para executarmos a ação correspondente. Para remover o incômodo processo de realizar tais testes, possibilitando a execução transparente da rotina correta, devemos usar o padrão Command capaz de dissociar os objetos da interface que geram o pedido de ação (comandos) daqueles que efetivamente irão realizá-la (Cooper, 1998, p. 65). Os objetos se tornarão responsáveis pelo acionamento das operações adequadas encapsularão tais ações, tornando-se formas mais genéricas de functors 4. Esse padrão é aplicável quando desejamos o isolamento entre os objetos requisitante e executor de uma ação; a requisição e o processamento da ação devem acontecer em instantes diferentes, permitindo assim que pedidos de ação sejam armazenados para processamento posterior, pois os objetos envolvidos são independentes; é desejável que a ação possa ser desfeita, pois o objeto que a realiza pode armazenar o estado anterior e as condições para sua recuperação; ou quando é necessário criarmos registros das operações realizadas. 439 Estrutura, participantes e conseqüências A estrutura desse padrão, como mostra a igura 6.7, compõe-se de cinco participantes. ± Classe Invoker Objetos dessa classe são os acionadores do comando, ou seja, responsáveis por efetuar o pedido de ação. ± Interface ICommand Especifica a interface a ser utilizada pelos objetos Invoker para acionar o comando. ± Classe CommandImpl Classe concreta que implementa a interface ICommand e que realiza a ligação entre o pedido de ação e a classe que efetivamente executa a ação (Receiver). 4. O termo functor é uma contração de function object, ou seja, um objeto que encapsula uma função, e foi cunhado por Coplien em sua discussão sobre idiomas e estilos de programação para C++ (Coplien, 1992). EDITORA FUTURA 06.pmd 439

36 MAIS JAVA ± Classe Receiver Classe responsável pela condução das operações necessárias à realização do comando solicitado. ± Classe Client Classe componente da aplicação que cria objetos ICommand e Receiver associados para possibilitar a execução de comandos. 440 Figura 6.7 Estrutura do padrão Command. Dessa forma, o cliente (Client) cria um objeto de comando (CommandImpl) registrando o objeto que executará os comandos (Receiver). No objeto acionador (Invoker) deve ser armazenado o objeto de comando (CommandImpl) correspondente à ação que deve ser realizada, de forma que (quando necessário) o acionador solicite a execução do comando. Como a interface ICommand é conhecida pelo Invoker, este é capaz de disparar a execução do comando por meio do objeto CommandImpl, no qual pode ser armazenado os estados dos objetos envolvidos, a fim de permitir que se desfaça tal comando. Assim, a interface ICommand permite que novos comandos sejam adicionados sem modificação das classes existentes, além de garantir que o Invoker e o Receiver estejam completamente desacoplados. Implementação e exemplo Apesar dos vários participantes, a implementação desse padrão é muito direta e simples. Podemos definir uma interface ICommand como apresentada no Exemplo 6.15, arbitrariamente pertencente a um pacote denominado notes. 06.pmd 440

37 Capítulo 6: Padrões de projeto // ICommand.java package notes; public interface ICommand { public void execute(); Exemplo 6.15 Interface Icommand. Em uma interface gráfica dotada de menus e botões (que faz o papel de Invoker), o acionamento desses componentes dispara a execução de ações distintas. Sendo assim, esses componentes deveriam fazer o papel do CommandImpl, mas como não são capazes de armazenar um objeto que possua a interface ICommand precisamos criar tal funcionalidade. Tomando um botão Swing comum (JButton) como componente desejado, poderíamos criar uma subclasse de JButton que ao mesmo tempo armazenasse um objeto ICommand e também implementasse tal interface, associando a funcionalidade do componente com a funcionalidade necessária para o padrão de projeto Command. Uma sugestão dessa implementação é dada na classe CommandJButton (Exemplo 6.16), também pertencente ao pacote notes. // CommandJButton.java package notes; public class CommandJButton extends javax.swing.jbutton implements ICommand { private ICommand command; // referência p/ comando associado public CommandJButton(String label, ICommand command) { super(label); // aciona construtor da superclasse this.command = command; // armazena comando associado 441 public CommandJButton(javax.swing.Icon icon, ICommand command) { super(icon); // aciona construtor da superclasse this.command = command; // armazena comando associado public void execute() { if (command!=null) command.execute(); Exemplo 6.16 Classe CommandJButton. Se estivéssemos construindo um editor de texto simples, seriam necessários comandos para criar um novo texto ( Novo ), abrir um arquivo ( Abrir ), salvar o conteúdo no arquivo atual ( Salvar ) ou em um outro arquivo ( Salvar como ), bem como encerrar a aplicação ou outras operações. Poderíamos empregar uma barra de botões para permitir que o usuário acionasse os comandos do editor. O uso do componente CommandJButton auxiliaria a implementação do editor, pois considerando que cada botão terá seu comando apropriado associado, o código necessário no processador de eventos dos botões (ActionListener) será bem simplificado, como pode ser visto nos fragmentos de código destacados na seqüência. EDITORA FUTURA 06.pmd 441

38 MAIS JAVA // criação de comando com argumentos necessários ICommand comando = new CommandImpl(...); // criação de botão-comando CommandJButton CommandJButton botao = new CommandJButton("NomeAção", comando); // registro do listener apropriado botao.addactionlistener(listener); : // no listener dos botões-comando public void actionperformed(actionevent e) { // executa ação associada aos botões ((CommandJButton) e.getsource()).execute(); Para implementarmos a ação Novo, devemos considerar quais as ações que devem ser realizadas: verificar se o conteúdo está salvo e preparar a área de edição para um novo documento, caso seja apropriado. Notamos que a execução desse comando necessita informações sobre o estado do documento e às vezes exibir uma mensagem de alteração. As outras ações Abrir, Salvar e Salvar Como também necessitam de informações sobre o estado do documento ou o nome do arquivo onde o documento deverá ser salvo. Decidimos assim ampliar as funcionalidades de uma área de texto JTextArea, fazendo com que a mesma mantenha uma variável indicando o nome do arquivo associado ao documento, e outra indicando se o conteúdo foi alterado. Para tornar tal componente sensível às alterações do texto contido, foi implementado um javax.swing.event.documentlistener, como indicado na classe CustomJTextArea. 442 // CustomJTextArea.java package notes; public class CustomJTextArea extends javax.swing.jtextarea implements javax.swing.event.documentlistener { private String contentname; // nome do arquivo associado private boolean changed; // flag de alteração de conteúdo public CustomJTextArea() { // construtor default contentname = null; changed = false; getdocument().adddocumentlistener(this); // métodos setter/getter p/ variável boleana changed public void setchanged(boolean changed) { this.changed = changed; public boolean ischanged() { return changed; // métodos setter/getter p/ variável String contentname public void setcontentname(string contentname) { this.contentname = contentname; public String getcontentname() { return contentname; 06.pmd 442

39 Capítulo 6: Padrões de projeto // implementação do DocumentListener public void changedupdate(javax.swing.event.documentevent e) { changed = true; // indica alteração public void insertupdate(javax.swing.event.documentevent e) { changed = true; // indica alteração public void removeupdate(javax.swing.event.documentevent e) { changed = true; // indica alteração Exemplo 6.17 Classe CustomJTextArea. As implementações da interface ICommand de nosso editor devem então ser parametrizadas com a instância do componente CustomJTextArea para que possam ter ciência do estado do documento além do nome do arquivo associado. Outro ponto importante é que mensagens de diálogo modais (típicas para a exibição de mensagens) necessitam de uma referência para o J rame responsável, a qual também deverá ser fornecida como parâmetro das implementações dos comandos. Segue nossa sugestão para a implementação do comando Novo mediante a classe NewCommand (Exemplo 6.18), que é o participante Receiver do padrão Command. // NewCommand.java package notes; import javax.swing.*; public class NewCommand implements ICommand { private J rame parent; private CustomJTextArea document; 443 public NewCommand(J rame parent, CustomJTextArea document) { this.parent = parent; this.document = document; public void execute() { // verifica se conteúdo está salvo if (document.ischanged()) { // avisa que conteúdo não está salvo int result = JOptionPane.showConfirmDialog(parent, "Texto não está salvo. Prosseguir?", "Aviso", JOptionPane.OK_CANCEL_OPTION); if (result==joptionpane.cancel_option) return; // cancela // limpa conteúdo document.settext(""); document.setcontentname(null); document.setchanged(false); Exemplo 6.18 Classe NewCommand. EDITORA FUTURA 06.pmd 443

40 MAIS JAVA Podemos observar que essa classe implementa a interface ICommand. O único construtor disponível recebe referências do J rame responsável e do componente CustomJTextArea usado para edição do texto. Na codificação do método execute(), exigido pela interface ICommand, temos a realização das operações associadas ao comando Novo, ou seja, a verificação se o conteúdo está ou não salvo. Estando salvo, a área de texto é preparada para uma nova edição, caso contrário exibe-se uma mensagem de aviso, permitindo que o usuário prossiga sem salvar ou cancele a operação. Os demais comandos necessários ao editor devem ser implementados de forma análoga. No diretório de exemplos do Capítulo 6, existe um subdiretório notes, no qual estão localizados todos os arquivos-fonte e as classes utilizadas para implementação integral desse exemplo. A construção do editor torna-se muito simples, considerando que as funcionalidades desejadas para os botões, a área de edição e dos comandos estão respectivamente encapsuladas nas classes CommandJButton, CustomJTextArea, NewCommand, OpenCommand, SaveCommand, SaveAsCommand, AboutCommand e ExitCommand. A classe principal, Notes (Exemplo 6.19), meramente organiza os elementos da interface, utilizando as classes adaptadas dos botões e área de texto, criando para cada comando do editor uma instância correspondente à sua implementação. 444 // Notes.java package notes; import java.awt.*; import java.awt.event.*; import javax.swing.*; public final class Notes extends J rame implements ActionListener { private ICommand exitcommand; public Notes() { super("notes"); // prepara área de texto CustomJTextArea text = new CustomJTextArea(); text.setlinewrap(true); text.setwrapstyleword(true); // prepara toolbar JToolBar tb = new JToolBar(); tb.add(createcommandjbutton( // new new ImageIcon("notes/imagens/New16.gif"), new NewCommand(this, text), this, "Novo")); tb.add(createcommandjbutton( // open new ImageIcon("notes/imagens/Open16.gif"), new OpenCommand(this, text), this, "Abrir...")); tb.add(createcommandjbutton( // save new ImageIcon("notes/imagens/Save16.gif"), new SaveCommand(this, text), this, "Salvar")); tb.add(createcommandjbutton( // saveas new ImageIcon("notes/imagens/SaveAs16.gif"), 06.pmd 444

41 Capítulo 6: Padrões de projeto new SaveAsCommand(this, text), this, "Salvar Como...")); tb.add(createcommandjbutton( // about new ImageIcon("notes/imagens/About16.gif"), new AboutCommand(this), this, "Sobre...")); exitcommand = new ExitCommand(this, text); // adiciona componentes na interface JScrollPane sp = new JScrollPane(text); sp.setborder(border actory.createetchedborder()); getcontentpane().add("center", sp); getcontentpane().add("north", tb); setdefaultcloseoperation(windowconstants.do_nothing_on_close); addwindowlistener(new WindowAdapter() { public void windowclosing(windowevent e) { exitcommand.execute(); ); setsize(300, 300); // cria e configura CommandJButton private CommandJButton createcommandjbutton(icon icon, ICommand cmd, ActionListener listener, String tooltip) { CommandJButton button = new CommandJButton(icon, cmd); button.addactionlistener(listener); button.settooltiptext(tooltip); return button; // ActionListener public void actionperformed(actionevent e) { ((ICommand)e.getSource()).execute(); 445 public static void main(string a[]) { new Notes().show(); Exemplo 6.19 Classe Notes. Devemos ressaltar que praticamente todo o código se concentra no construtor, onde uma barra de ferramentas é criada para organizar os botões CommandJButton, cuja instanciação e configuração é realizada pelo método createcommandjbutton(icon, ICommand). As implementações da interface ICommand são criadas fornecendo-se as referências do J rame da aplicação e do componente CustomJTextArea usado para edição. A implementação do método actionperformed(actionevent), exigida pelo ActionListener declarado, toma uma única linha, pois todos os componentes que disparam tal evento são implementações da interface ICommand onde as ações podem ser disparadas por meio do acionamento do método execute(). Executando essa aplicação, teríamos: EDITORA FUTURA 06.pmd 445

42 MAIS JAVA Figura 6.8 Aplicação Notes. O uso do padrão de projeto Command proporcionou os seguintes ganhos nessa aplicação: ± Cada classe tem melhor definida suas responsabilidades (maior coesão), e com isso são menores e mais fáceis de serem compreendidas; e 446 ± Substituindo-se ou alterando-se as implementações concretas de ICommand, ou seja, as classes NewCommand, OpenCommand, SaveCommand, SaveAsCommand, AboutCommand e ExitCommand, modificamos as funcionalidades da aplicação sem que seja necessário modificar sua interface ou os componentes customizados (baixo acoplamento). Usos conhecidos e padrões relacionados Como vimos, a construção de interfaces gráficas e ou de processadores de comandos podem ser melhoradas com o uso desse padrão. Temos ainda que múltiplos comandos podem ser agregados por meio do padrão Composite, permitindo a construção de macros. O armazenamento de estados poderia ser realizado por intermédio do padrão Memento (Gamma et al., 1995), permitindo que ações realizadas possam ser desfeitas (undo) Decorator Motivação, propósito e aplicabilidade Quando desejamos adicionar novas responsabilidades a objetos de uma certa classe, uma alternativa é adicionarmos as características desejadas em novas classes derivadas da primeira, ou seja, por meio do mecanismo da herança, criamos subclasses adicionando tais responsabilidades. Embora seja conceitualmente correto, esse mecanismo pode revelar-se inflexível, pois nem sempre 06.pmd 446

43 Capítulo 6: Padrões de projeto desejamos que os objetos tenham tais funcionalidades e que é um preceito da orientação a objetos, no qual as classes não devem conter características que usualmente não sejam usadas. O propósito do padrão de projeto Decorator é a adição de novas responsabilidades a um objeto participante, representando uma alternativa ao mecanismo da herança, pois durante a vida do objeto tais responsabilidades poderão ser adicionadas ou mesmo removidas, efeito que não pode ser obtido por meio da herança. Resumidamente, esse padrão permite que novas responsabilidades sejam adicionadas aos objetos em tempo de execução, sendo um mecanismo mais flexível que a herança, que faz o mesmo em tempo de compilação (Geary, 2001). O objeto a ser decorado, isto é, que terá novas responsabilidades adicionadas, é inserido em um outro, o decorador, que efetivamente provê as novas funcionalidades para o primeiro e de forma completamente transparente. O objeto decorador só muda o exterior do objeto decorado, assim este não precisa conhecer nada sobre o decorador. Como usualmente não se distingue um objeto de outro decorado, todos os pedidos de ação feitos para o objeto são, na verdade, realizados sobre o decorador que reveste o objeto decorado. O decorador envia ao objeto contido todos os pedidos de ação recebidos, podendo a seu critério conduzir as novas operações antes ou depois de tal encaminhamento. Isso implica que o objeto decorador deve oferecer a mesma interface do objeto decorado. Desta forma, o objeto decorador também poderá ser decorado, possibilitando que um objeto receba um número ilimitado de responsabilidades adicionais. Outra implicação é que o decorador é um adorno que poderá ser retirado do objeto, quando for conveniente. O padrão Decorator é então aplicável às seguintes situações: ± Quando desejamos adicionar transparentemente responsabilidades a componentes individuais, sem afetar outros objetos do mesmo tipo. 447 ± Quando desejamos que as novas responsabilidades possam ser retiradas. ± Quando existe um número tal de combinações entre os objetos e as funcionalidades individuais que a solução, por meio da construção de subclasses, provocaria uma explosão de novas classes (Gamma, 1995, p. 177). Estrutura, participantes e conseqüências A estrutura do padrão Decorator é composta por quatro participantes diferentes e é ilustrada na igura 6.9. ± Classe Component Classe abstrata que define a interface para os objetos que poderão ter novas responsabilidades adicionadas ou retiradas;. Implementa operações comuns à hierarquia de componentes proposta. ± Classe ComponentImpl Implementações particulares dos componentes que terão incorporadas novas funcionalidades. EDITORA FUTURA 06.pmd 447

44 MAIS JAVA ± Classe Decorator Classe abstrata que deve possuir interface semelhante a Component. Mantém uma referência para o objeto decorado. ± Classe DecoratorImpl Adiciona efetivamente as novas responsabilidades ao objeto decorado. Encaminha os pedidos de ação ao objeto para que tenha comportamento transparente. 448 Figura 6.9 Estrutura do padrão Decorator. Como conseqüência do uso desse padrão, temos: ± Representa um mecanismo mais flexível que a herança. ± Novas implementações de decoradores (DecoratorImpl) podem ser adicionadas à hierarquia de componentes, possibilitando a adição de novas responsabilidades, sem que essas tenham que ser previstas durante o projeto. ± Novos tipos de objetos (ComponentImpl) podem ser igualmente adicionados sem que sua necessidade seja prevista. ± Implica na existência de um grande número de objetos com responsabilidades muito restritas, ou seja, embora seja uma estrutura mais versátil é também mais complexa de ser compreendida e utilizada. 06.pmd 448

45 Capítulo 6: Padrões de projeto Implementação e exemplo Como vimos, a estrutura desse padrão requer uma classe base Component que especifica a interface de seus participantes e a implementação básica de algumas das operações comuns. A classe Quantidade (Exemplo 6.20) especifica a interface para definição e armazenamento de um valor, bem como obtenção de sua representação textual. // Quantidade.java public abstract class Quantidade { // retorna o valor associado como objeto Number public abstract Number obtemvalor(); // define o valor associado através de um Number public abstract void definevalor(number valor); // obtém uma representação textual da Quantidade public abstract String tostring(); Exemplo 6.20 Classe Quantidade. Poderíamos implementar um componente QuantidadeInteira para armazenar quantidades inteiras, adequando tais operações às novas características desejadas, como no Exemplo // QuantidadeInteira.java public class QuantidadeInteira extends Quantidade { // armazenamento do valor inteiro associado private Integer valor; // construtor parametrizado com Integer public QuantidadeInteira(Integer valor) { this.valor = valor; 449 // construtor parametrizado com inteiro public QuantidadeInteira(int valor) throws Number ormatexception { this.valor = new Integer(valor); // retorna o valor associado public Number obtemvalor() { return valor; // define o valor associado public void definevalor(number valor) { this.valor = (Integer)valor; // obtém uma representação textual public String tostring() { return new String(valor.toString()); Exemplo 6.21 Classe QuantidadeInteira. EDITORA FUTURA 06.pmd 449

46 MAIS JAVA Por intermédio dessa classe, podemos armazenar quantidades inteiras quaisquer, como no trecho de código que segue, tratadas polimorficamente por meio da classe Quantidade: // cria um objeto Quantidade quant = new Quantidade(12); // exibe valor no console System.out.println(quant); // obtém valor armazenado Integer valorinteiro = (Integer) quant.obtemvalor(); Para que esse componente possa ser decorado, isto é, para que seja possível adicionarmos algumas responsabilidades novas a objetos selecionados, precisamos definir uma classe com a mesma interface que Quantidade (raiz dessa hierarquia) capaz de conter um objeto desse tipo e encaminhado a tal objeto todos os pedidos recebidos. A adição de novas funcionalidades para o componente se dará antes ou depois do encaminhamento das operações disponíveis. Vejamos na classe Decorador, relacionada no Exemplo 6.22, como isso poderia ser feito. // Decorador.java public abstract class Decorador extends Quantidade { // referência para componente Quantidade armazenado protected Quantidade quantidade; 450 // construtor parametrizado com instância de Quantidade public Decorador(Quantidade quantidade) { this.quantidade = quantidade; // encaminha definição do valor associado public void definevalor(number valor) { quantidade.definevalor(valor); // encaminha pedido e retorna o valor associado public Number obtemvalor() { return quantidade.obtemvalor(); // encaminha pedido e retorna representação textual public String tostring() { return quantidade.tostring(); // define o valor associado através de um Number Exemplo 6.22 Classe Decorador. A classe Decorador, por intermédio de seu construtor parametrizado, armazena uma referência para o componente a ser contido (aquele que será decorado). Todas as operações realizadas sobre objetos Decorador são encaminhadas para os objetos contidos, pois sua interface é a mesma definida pela classe Quantidade. Subclasses de Decorador podem substituir os métodos apropriados para adicionar as novas funcionalidades decorativas, tal como realizado pela classe 06.pmd 450

47 Capítulo 6: Padrões de projeto Unidade (Exemplo 6.23), que adiciona um sufixo contendo a unidade relacionada à quantidade armazenada por objetos Quantidade, e Prefixo (Exemplo 6.24) que acrescenta um prefixo livre a tais objetos. // Unidade.java public class Unidade extends Decorador { // armazenamento da unidade private String unidade; // construtor parametrizado public Unidade(Quantidade quantidade, String unidade) { super(quantidade); defineunidade(unidade); // unidade (decoração) é adicionada *depois* // da representação textual do objeto contido public String tostring() { return new String(quantidade.toString()+unidade); // novas operações para definição e obtenção da Unidade public void defineunidade(string unidade) { this.unidade = unidade; public String obtemunidade() { return unidade; Exemplo 6.23 Classe Unidade. 451 Devemos notar que o construtor parametrizado recebe tanto o componente a ser decorado como uma string com a unidade que corresponde à decoração em si. Apenas o método tostring(), que especificamente adiciona a funcionalidade desejada, deveria ser implementado (além do construtor). Esse método aciona a representação textual do objeto contido e acrescenta ao final desta a unidade definida, produzindo o efeito desejado. A implementação de novas operações nas implementações dos decoradores, no caso os métodos defineunidade(string) e obtemunidade(), é opcional. Para decorarmos um objeto do tipo quantidade, bastaria fazer: // cria um objeto Quantidade quant = new Quantidade(12); // exibe valor no console System.out.println(quant); // decora objeto com unidade Quantidade quantunidade = new Unidade(quant, "Kg"); Exemplo 6.24 Classe Prefixo. A classe Prefixo (Exemplo 6.24) é estruturalmente semelhante à classe Unidade, exceto pela forma que o prefixo é adicionado (o mesmo a adicionado antes da representação textual do objeto contido). EDITORA FUTURA 06.pmd 451

48 MAIS JAVA // Prefixo.java public class Prefixo extends Decorador { // armazenamento do prefixo private String prefixo; // construtor parametrizado public Prefixo(Quantidade quantidade, String prefixo) { super(quantidade); defineprefixo(prefixo); // prefixo (decoração) é adicionado *antes* // da representação textual do objeto contido public String tostring() { return new String(prefixo+quantidade.toString()); // novas operações para definição e obtenção do prefixo public void defineprefixo(string prefixo) { this.prefixo = prefixo; public String obtemprefixo() { return prefixo; 452 O programa TestaDecoradores (Exemplo 6.25) cria um objeto Quantidade, que é sucessivamente decorado, mostrando que a implementação exemplificada admite que os decoradores possam também ser decorados, de forma que os objetos básicos possam receber múltiplas combinações de decoração. // TestaDecoradores.java public class TestaDecoradores { public static void main(string a[]) { // um "componente" simples Quantidade qsimples = new QuantidadeInteira(110); System.out.println(qSimples); // "componente" com unidade Quantidade qunidade = new Unidade(qSimples, "m"); System.out.println(qUnidade); // "componente" com prefixo Quantidade qprefixo = new Prefixo(qSimples, "Comp: "); System.out.println(qPrefixo); // "componente" com dupla unidade Quantidade qunidcomposta = new Unidade(qUnidade, "/s"); System.out.println(qUnidComposta); 06.pmd 452

49 Capítulo 6: Padrões de projeto Exemplo 6.25 // "componente" com prefixo e unidade Quantidade qprefixunid = new Prefixo(qUnidade, "L = "); qprefixunid.definevalor(new Integer(95)); System.out.println(qPrefixUnid); // "componente" com prefixo e unidade dupla Quantidade qprefixunid2 = new Prefixo(qUnidComposta, "Vel. "); qprefixunid.definevalor(new Integer(95)); System.out.println(qPrefixUnid2); Classe TestaDecoradores. Executando o programa TestaDecoradores, obteremos resultados semelhantes ao abaixo: >java TestaDecoradores m Comp: m/s L = 95m Vel. 95m/s Os princípios básicos da implementação vista permitem que esse padrão seja aplicado em outras situações, possibilitando obter grande flexibilidade e elegância. 453 Os containers AWT e Swing armazenam internamente os diversos componentes mantidos sob suas responsabilidades. Utilizando os métodos getcomponentcount() e getcomponent(int), tal como definidos na classe abstrata java.awt.container, é possível determinar dinamicamente quantos e quais componentes existem dentro desses containers. Seria desejável que tais containers pudessem ter seus componentes obtidos da mesma forma que os objetos de coleções, isto é, por meio da interface java.util.iterator, que oferece uma semântica precisa e mais geral para tais operações. Na classe ContainerIteratorDecorator, disponível no diretório de exemplos do Capítulo 6, temos um Decorator degenerado, isto é, um decorador que permite obter os componentes disponíveis em um container AWT ou Swing, mas que não permite acesso às demais características do objeto decorado. A aplicação QuemEstaContido (que usa esse decorador) permite determinar os componentes contidos em qualquer classe JFrame ou Frame, cujo nome é informado. Usos conhecidos e padrões relacionados Na API Java voltada para tratamento de entrada e saída, as diversas implementações de streams existentes devem ser combinadas para que seu uso seja possível, ilustrando o emprego do padrão de projeto Decorator (Jandl, 2002, p. 379, Geary, 2001). A leitura de um arquivo com texto empregaria: EDITORA FUTURA 06.pmd 453

50 MAIS JAVA // abertura do arquivo desejado ilereader arquivo = new ilereader("nomedoarquivo"); // adição de leitura otimizada através de buffer de leitura e outras // operações especializadas na leitura de texto (leitura linha a linha) BufferedReader entrada = new BufferedReader(arquivo); A mesma funcionalidade poderia ser obtida assim: // abertura e leitura bufferizada do arquivo de texto desejado BufferedReader entrada = new BufferedReader( new ilereader("nomedoarquivo")); A forma compactada obscurece o fato de termos um objeto associado ao arquivo de texto desejado (a instância de ilereader que é o objeto decorado), o qual é adicionado a um decorador (a instância de BufferedReader), que oferece operações de leitura otimizadas por meio de um buffer, além de uma interface especializada em operações voltadas para arquivos de texto. A leitura de um arquivo de texto poderia ser realizada com um trecho como o abaixo: 454 try { // variável arquivo contém o nome do arquivo ilereader fr = new ilereader(arquivo); BufferedReader br = new BufferedReader(fr); String linha; while((linha=br.readline())!=null) { System.out.println(linha); br.close(); catch (IOException ioe) { ioe.printstacktrace(); Existe outro decorador, a classe LineNumberReader, que possibilita o controle adicional da numeração das linhas, ou seja, permite acompanhar o número da linha lida. A leitura de um arquivo de texto controlando-se a numeração das linhas é idêntica ao trecho anterior: try { ilereader fr = new ilereader(a[0]); LineNumberReader lnr = new LineNumberReader(fr); String linha; while((linha=lnr.readline())!=null) { System.out.println(lnr.getLineNumber()+":\t"+linha); lnr.close(); catch (IOException ioe) { ioe.printstacktrace(); Esses dois decoradores poderiam ser combinados com os outros tipos de reader (tais como PushbackReader ou InputStreamReader), permitindo inúmeras possibilidades de utilização, o que é nitidamente mais vantajoso que a implementação de uma subclasse específica para cada 06.pmd 454

51 Capítulo 6: Padrões de projeto combinação. As demais famílias de streams da API de entrada e saída seguem o mesmo conceito, isto é, existem algumas classes básicas que podem ser decoradas com outras, proporcionando funcionalidades mais adequadas. No diretório de exemplos do Capítulo 6, temos a classe DecoradoresIO que exemplifica o uso de alguns tipos básicos de streams e diversos decoradores existentes no pacote java.io. Dentro da família de componentes Swing também existem alguns exemplos do emprego do padrão de projeto Decorator. O componente JScrollPane permite que o componente adicionado seja decorado com barras de rolagem, o que é usualmente feito com áreas de texto JTextArea, caixas de lista JLista, painéis JPanel, tabelas JTable etc. inalmente, o padrão Decorator, que agrega novas funcionalidades a um componente, deve ser distinguido de outros semelhantes como o Adapter, que provê uma interface diferente para as mesmas funcionalidades (6.6.8); o Strategy, que modifica a funcionalidade associada a um objeto (6.6.7); e o Composite, cujo objetivo é agregar diferentes objetos como uma unidade (6.6.4) Strategy Motivação, propósito e aplicabilidade Existem situações onde uma determinada operação pode ser realizada por meio de diferentes algoritmos, cada um oferecendo certas vantagens e desvantagens ou simplesmente possuindo características distintas. Provavelmente em uma situação, o melhor algoritmo para realizar essa operação seria diferente do escolhido para realizar a mesma em outro contexto. Isso sugere que pode não existir um único algoritmo ideal para todos os casos, mas uma família de algoritmos, cada um conveniente para um determinado contexto. 455 O padrão de projeto Strategy, também conhecido como Policy, permite encapsular uma família de algoritmos, dotando-os de uma interface comum, de forma que possam ser usados livremente uns no lugar dos outros, isto é, as classes que necessitam do serviço prestado por tais algoritmos não mais os implementarão internamente, mas utilizarão objetos das classes que implementam tal interface e que efetivamente implementam os algoritmos desejados. Isso caracteriza um padrão de comportamento. Com isso, separamos o contexto de utilização de um algoritmo de sua implementação, possibilitando que os algoritmos empregados sejam substituídos por outros transparentemente; algoritmos diferentes sejam escolhidos dinamicamente, conforme a situação; sejam mantidos separados os dados (e estruturas eventualmente complexas) dos algoritmos em si. EDITORA FUTURA 06.pmd 455

52 MAIS JAVA Estrutura, participantes e conseqüências Esse padrão possui três participantes, como pode ser observado na igura 6.10: ± Interface IStrategy Define as operações a serem disponibilizadas por toda a família de algoritmos. Isola as implementações concretas dos algoritmos do contexto de sua utilização. ± Classe StrategyImpl amília de classes que implementam os algoritmos necessários possibilitando seu uso por meio da interface IStrategy. ± Classe Context Classe que utiliza um objeto StrategyImpl para delegar a execução de certas operações por meio de uma interface conhecida (IStrategy). 456 Figura 6.10 Estrutura do padrão Strategy. Implementação e exemplo O processamento de expressões aritméticas pode ser realizado por parsers, na verdade tradutores dirigidos por sintaxe dotados de capacidades de interpretação (Aho et al., 1995, p. 15). As expressões aritméticas podem ser expressas em notação infixa, pós-fixa e pré-fixa : 5 * / 4-1 infixa operadores dispostos entre os operandos. 5 2 * 3 4 / pós-fixa operadores dispostos após os operandos. - + * 5 2 / pré-fixa operadores dispostos antes dos operandos. Para que seja possível calcular o resultado de expressões escritas em qualquer uma dessas notações, devemos possuir um parser dotado do algoritmo de análise e avaliação adequado. Isso 06.pmd 456

53 Capítulo 6: Padrões de projeto significa que se necessitássemos construir uma aplicação capaz de avaliar expressões infixas e pósfixas, deveríamos utilizar dois desses três algoritmos, conforme selecionado ou configurado pelo usuário. Seria muito interessante isolarmos a aplicação (e seus dados) dos algoritmos, permitindo que novas versões dos algoritmos existentes ou até mesmo novos algoritmos pudessem ser facilmente adicionados. A aplicação é o participante Context, que contém os dados a serem processados pelo algoritmo e por isso mantém uma referência para objetos que implementam a interface IStrategy. Como lidaremos com parsers, denominaremos a interface comum desses algoritmos de IParser, a qual será dotada das operações relacionadas no Exemplo // IParser.java public interface IParser { // submete uma expressão para avaliação public void parse(string expression); // obtém último resultado public Double getlastresult(); // obtém iterator para tabela de variáveis public java.util.iterator iterator(); // reinicia tabela de variáveis do parser public void reset(); Exemplo 6.26 Interface Iparser. Com isso, as implementações dos parsers (os participantes StrategyImpl) deverão ser capazes de avaliar uma expressão, obter o resultado da avaliação, navegar pela tabela de variáveis do parser e reiniciá-lo. Uma implementação de um parser, para notação infixa, poderia ser denominado In ixparserimpl, como esquematicamente relacionado no Exemplo // In ixparserimpl.java public class In ixparserimpl implements IParser { // inicia o processamento da atribuição public void parse(string expressao) {... // retorna último resultado avaliado public Double getlastresult() {... // reinicializa parser public void reset() {... // retorna um objeto iterator para navegar tabela de variáveis public Iterator iterator() {... Exemplo 6.27 Classe InFixParserImpl. EDITORA FUTURA 06.pmd 457

54 MAIS JAVA Analogamente, poderíamos implementar outro parser destinado à avaliação de expressões em notação pós-fixa, em uma classe Pos ixparserimpl, cuja estrutura é idêntica à classe In ixparserimpl, mas empregando um algoritmo diferente para o processamento das expressões recebidas. As versões completas das classes InFixParserImpl e PosFixP osfixparserimpl estão disponíveis no diretório de exemplos do Capítulo 6. Os erros eventualmente detectados pelos parsers serão sinalizados por meio de objetos da classe ParserException, uma subclasse das exceções de execução, cujo tratamento não é obrigatório, como mostra o código do Exemplo // ParserException.java public class ParserException extends RuntimeException { public ParserException(String message) { super(message); Exemplo 6.28 Classe ParserException. 458 Para isolarmos completamente a aplicação dos algoritmos utilizados, combinaremos esse padrão com uma fábrica de objetos (uma implementação de actory Method), que nos permitirá obter instâncias dos algoritmos necessários sem que sejam conhecidos os nomes das classes usadas para a criação de tais objetos. A interface dos produtos dessa fábrica é a mesma da família de algoritmos, ou seja, IParser. Uma implementação possível dessa fábrica (classe Parser actory) encontra-se relacionada no Exemplo // Parser actory.java public class Parser actory { // tipos disponíveis private final static String types[] = { "In ix", "Pos ix" ; // retorna "produtos" disponíveis public static String[] getavailableparsers() { return types; // cria um "produto" conforme tipo dado public static IParser createparser(string parsername) throws ParserNotAvailableException { if (parsername.equals(types[0])) return new In ixparserimpl(); if (parsername.equals(types[1])) return new Pos ixparserimpl(); throw new ParserNotAvailableException(parserName); Exemplo 6.29 Classe ParserFactory. 06.pmd 458

55 Capítulo 6: Padrões de projeto Devemos ressaltar que, caso sejam fornecidas strings de identificação inválidas, o método createparser(string) lança a exceção ParserNotAvailableException (o tratamento dessa exceção também não é obrigatório, pois é uma subclasse de java.lang.runtimeexception). // ParserNotAvailableException.java public class ParserNotAvailableException extends RuntimeException { public ParserNotAvailableException(String message) { super(message); Exemplo 6.30 Classe ParserNotAvailableException. Segue uma aplicação Swing (classe StrategyDemo) que dispõe seus componentes em um painel organizado com o layout GridLayout. No construtor é instanciado um objeto Parser actory (uma fábrica), por meio do qual se obtém as strings de identificação dos objetos IParser que podem ser criados. Essas strings são usadas para preencher uma caixa de seleção (JComboBox), que permite ao usuário a escolha do tipo de parser. Por meio de uma caixa de texto (JText ield), o usuário pode fornecer a expressão que será avaliada com o parser escolhido. Classes anônimas implementam um ActionListener separado para a caixa de seleção e caixa de texto, o que desvia a execução respectivamente para os métodos cbparsernameenter() e tfexpressionenter(). O primeiro método determina o nome do parser selecionado na caixa de seleção com o qual obterá o objeto IParser equivalente. O segundo método efetua a avaliação da expressão dada na caixa de texto por meio do objeto parser atual, que depende da seleção realizada, exibindo o resultado em um rótulo (JLabel), posicionado na parte inferior da janela. 459 // StrategyDemo.java import java.awt.*; import java.awt.event.*; import javax.swing.*; public class StrategyDemo extends J rame { // componentes da interface private JComboBox cbparsername; private JText ield tfexpression; private JLabel lresult; private IParser parser = null; // construtor public StrategyDemo() { super("strategydemo"); // organiza componentes na interface JPanel p = new JPanel(new GridLayout(6, 1)); p.add(new JLabel("Tipo de Parser")); // obtém nomes dos parsers disponíveis para JComboBox String nomes[] = Parser actory.getavailableparsers(); p.add(cbparsername = new JComboBox(nomes)); p.add(new JLabel("Expressão")); p.add(tfexpression = new JText ield(25)); p.add(new JLabel("Resultado")); p.add(lresult = new JLabel()); EDITORA FUTURA 06.pmd 459

56 MAIS JAVA getcontentpane().add("center", p); // registra listeners para componentes cbparsername.addactionlistener(new ActionListener() { public void actionperformed(actionevent e) { cbparsernameenter(); ); cbparsernameenter(); // provoca inicialização do parser tfexpression.addactionlistener(new ActionListener() { public void actionperformed(actionevent e) { tfexpressionenter(); ); // outros ajustes setdefaultcloseoperation(j rame.exit_on_close); pack(); // processa seleção de parser private void cbparsernameenter() { try { parser = Parser actory.createparser( (String)cbParserName.getSelectedItem()); catch (ParserNotAvailableException pnae) { lresult.settext(pnae.tostring()); 460 // processa expressão dada através do parser private void tfexpressionenter() { try { parser.parse(tfexpression.gettext()); Double result = parser.getlastresult(); lresult.settext(" = " + result.tostring()); catch (ParserException pe) { lresult.settext(pe.tostring()); // inicia aplicação public static void main(string a[]) { new StrategyDemo().show(); Exemplo 6.31 Classe StrategyDemo. Executando essa aplicação, poderíamos selecionar um dos parsers disponíveis para avaliação de uma expressão aritmética, como mostra a igura Ressaltamos que todas as expressões fornecidas devem ser atribuições, isto é, uma variável recebendo uma expressão na notação em uso. Tanto o nome da variável como o último valor recebido são armazenados internamente pelos parsers, possibilitando que expressões subseqüentes utilizem os valores contidos nessas variáveis, empregando-as diretamente nas expressões. Isso é possível desde que mantido o parser em uso, pois alterando-se a seleção do parser, um novo objeto é criado, e assim inicia-se uma nova tabela de variáveis/valores. 06.pmd 460

57 Capítulo 6: Padrões de projeto Figura 6.11 Aplicação StrategyDemo. Devemos ressaltar que a aplicação StrategyDemo não necessita de nenhuma informação sobre as classes concretas In ixparserimpl e Pos ixparserimpl, mostrando como os padrões actory Method e Strategy permitem isolar a aplicação das classes usadas, da criação de seus objetos e também de algoritmos particulares. Toda a manipulação dos produtos (os algoritmos fornecidos pela fábrica) é realizada por meio da interface IParser. Usos conhecidos e padrões relacionados Como foi visto, o padrão de projeto Strategy pode ser associado com vantagens ao padrão actory Method (6.6.3) para constituir aplicações configuráveis dinamicamente, permitindo que seu comportamento seja adequado às necessidades de uma determinada situação. 461 Um exemplo do emprego do padrão Strategy na API Java é a forma com que os containers destinados a componentes visuais AWT e Swing delegam a tarefa de dimensionar e posicionar os componentes contidos. Todos os containers dessas famílias, por exemplo, java.awt.panel e javax.swing.panel, utilizam objetos que implementam as interfaces java.awt.layoutmanager ou java.awt.layoutmanager2, os quais são responsáveis pelas tarefas de determinar o tamanho e a posição dos componentes no container segundo regras específicas. As classes que implementam essas interfaces são os chamados gerenciadores de layout ou layout managers (Horstmann & Cornell, 2001A, p. 339; Jandl, 2002, p. 184): BorderLayout, lowlayout, GridLayout etc. Tais objetos podem ser dinamicamente alterados, sem que isso afete os containers, permitindo que o arranjo dos componentes varie livremente. Além disso, novos gerenciadores de layout podem ser implementados e utilizados pelos containers, abrindo inúmeras alternativas novas Adapter Motivação, propósito e aplicabilidade Ao implementarmos um conjunto de classes sempre temos alguns objetivos em mente. Mesmo que essas classes sejam projetadas de forma que seu uso seja o mais amplo possível, permitindo EDITORA FUTURA 06.pmd 461

58 MAIS JAVA que sejam incorporadas em um toolkit ou framework, é possível que não possamos utilizar tais classes em um projeto específico porque suas interfaces são inapropriadas para uso direto. O padrão de projeto Adapter tem como único propósito permitir o uso de uma classe existente por meio da interface necessária, possibilitando o reaproveitamento de implementações existentes. A solução delineada por esse padrão se aplica, portanto, a todos os casos onde desejamos utilizar uma classe disponível por meio de uma interface diferente da originalmente projetada. Como o comportamento da classe adaptada é, em última análise, preservado, temos que esse padrão é do tipo estrutural. Estrutura, participantes e conseqüências A igura 6.12 mostra os participantes desse padrão. 462 Figura 6.12 Estrutura do padrão Adapter. ± Classe Adaptee Classe que desejamos utilizar e que possui interface incompatível com a aplicação Client. ± Classe Client Classe ou conjunto de classes que necessita utilizar a classe Adaptee, mas por meio de uma interface particular. ± Interface IAdapter Interface necessária para que uma classe possa ser utilizada pela aplicação Client. É a interface das classes adaptadoras. ± Classe AdapterImpl Subclasse de Adaptee que implementa a interface IAdapter. Possibilita que o Client utilize objetos Adaptee por meio da interface IAdapter. A classe AdapterImpl é construída por intermédio da herança como uma subclasse de Adaptee, permitindo que mesmo sem seu código-fonte possamos criar uma classe com toda a 06.pmd 462

59 Capítulo 6: Padrões de projeto funcionalidade disponível em Adaptee, ou seja, todas as operações específicas existentes na classe Adaptee continuam disponíveis na classe AdapterImpl. Essa estratégia não poderá ser utilizada caso a classe Adaptee seja implementada como final, o que impede que as classes assim declaradas sejam estendidas por meio da herança. Neste caso, a classe AdapterImpl deve instanciar e manter a referência para um objeto Adaptee (agregação), operando sobre tal referência. Nesse caso, teremos um adaptador de objeto (object adapter) em vez de um adaptador de classe (class adapter), como discutido. No diretório de exemplos do Capítulo 6, temos um exemplo de implementação de um object adapter: a classe IteratorAdapter adapta o uso de objetos java.util.enumeration para a interface IIterator (veja o Exemplo 6.3), permitindo que objetos java.util.vector ou java.util.hastable tenham seus objetos percorridos com iterators especificados conforme essa interface. A aplicação TestaIteratorAdapter exemplifica tal uso. A classe AdapterImpl também deve implementar os métodos especificados pela interface Iadapter, de modo que seu uso acione os métodos correspondentes especificados em sua superclasse Adaptee. Não é necessário existir uma correspondência direta entre os métodos da classe adaptada e da interface adaptadora, ou seja, uma combinação de métodos da classe Adaptee pode ser utilizada para cada método da interface IAdapter e vice-versa. 463 Implementação e exemplo Vamos supor que tenhamos construído um componente Swing muito simples, capaz de exibir um gráfico de dispersão composto de uma série de pontos (x, y). Tal componente herda da classe javax.swing.jcomponent as habilidades básicas de componente GUI, adicionando uma lista de pontos a serem exibidos utilizando um ArrayList, operações básicas de adição e remoção desses pontos (add(point) e remove(point)), controle elementar de uma grade de referência (setgridsize(int) e getgridsize()) e uma rotina de renderização adequada, como sugerido no Exemplo // XYPanel.java import java.awt.*; import java.util.list; import java.util.*; import javax.swing.*; public class XYPanel extends JComponent { private List pontos = new ArrayList(); // lista de pontos private int gridsize = 50; // tamanho da grade EDITORA FUTURA 06.pmd 463

60 MAIS JAVA // adiciona pontos ao gráfico public boolean add(point p) { if (p.x>-1 && p.y>-1) { pontos.add(p); return true; return false; // remove pontos do gráfico public boolean remove(point p) { Iterator it = pontos.iterator(); while (it.hasnext()) { if (it.next().equals(p)) { it.remove(); return true; return false; // ajusta tamanho da grade public void setgridsize(int size) { if (size>0) gridsize = size; 464 // obtém tamanho da grade public int getgridsize() { return gridsize; // rotina de renderização do componente public void paintcomponent(graphics g) { Dimension tam = getsize(); // desenha grade g.setcolor(getbackground().darker()); for(int x=gridsize; x<tam.width; x+=gridsize) g.drawline(x, 0, x, tam.height); for(int y=gridsize; y<tam.width; y+=gridsize) g.drawline(0, y, tam.width, y); // desenha pontos g.setcolor(get oreground()); Iterator it = pontos.iterator(); while (it.hasnext()) { Point p = (Point)it.next(); int y = tam.height - p.y; g.drawoval(p.x-1, y-1, 3, 3); Exemplo 6.32 Classe XYPanel. Se há necessidade de utilizarmos esse componente em uma situação onde são fornecidas coordenadas polares por meio de operações diferentes, podemos converter tais pontos para 06.pmd 464

61 Capítulo 6: Padrões de projeto coordenadas cartesianas, ou construir um novo componente, ou aplicar o padrão Adapter e realizar a adaptação da interface existente da classe XYPanel para outra necessária. Tomando a interface IPolarPanel, declarada no Exemplo 6.33 e que especifica as novas operações necessárias, podemos criar uma classe adaptadora para que o componente XYPanel seja utilizado na nova situação. // IPolarPanel.java public interface IPolarPanel { public void plot(int radius, double angle); public void unplot(int radius, double angle); public void adjustpencolor(int r, int g, int b); Exemplo 6.33 Interface IpolarPanel. A classe adaptadora deve estender XYPanel, de modo a herdar todas as suas operações e, ao mesmo tempo, implementar a interface IPolarPanel, possibilitando disponibilizar as novas operações traduzindo-as em termos das operações existentes. Isso é feito na classe PolarToXYPanelAdapter (Exemplo 6.34). // PolarToXYPanelAdapter.java import java.awt.*; // classe adaptadora public class PolarToXYPanelAdapter extends XYPanel implements IPolarPanel { // adição de ponto ao gráfico public void plot(int radius, double angle) { add(convert(radius, angle)); 465 // remoção de ponto do gráfico public void unplot(int radius, double angle) { remove(convert(radius, angle)); // ajuste da cor dos pontos public void adjustpencolor(int r, int g, int b) { set oreground(new Color(r, g, b)); // método auxiliar na conversão de coordenadas // polares para cartesianas private Point convert(int radius, double angle) { int x = (int)(radius * Math.cos(angle)); int y = (int)(radius * Math.sin(angle)); return new Point(x, y); Exemplo 6.34 Classe PolarToXYPanelAdapter. Por meio dessa classe, podemos utilizar as funcionalidades existentes na classe XYPanel usando-a com uma nova interface (IPolarPanel), sem que com isso tenhamos que construir um novo EDITORA FUTURA 06.pmd 465

62 MAIS JAVA componente, simplificando o projeto ao mesmo tempo que isolamos a implementação da interface utilizada. Na igura 6.13, temos ilustrado o uso simples da classe adaptada (XYPanel) e da classe adaptadora (PolarToXYPanelAdapter). Figura 6.13 Aplicações XYPanelTest e PolarPanelTest. O código-fonte das aplicações XYPanelT aneltest est e PolarP olarpanelt aneltest est localiza-se no diretório de exemplos do Capítulo Usos conhecidos e padrões relacionados O padrão de projeto Adapter converte a interface de uma classe existente em outra necessária, mas não inclui funcionalidades adicionais. O padrão acade (Gamma et al., 1995, p. 185; Davis, 1999) realiza tarefa semelhante, fornecendo a interface desejada para um conjunto de classes (e não apenas para uma, como no caso do Adapter). O padrão Decorator (6.6.6) tem diferente propósito, pois adiciona funcionalidades novas, recursivamente sem alterar a interface existente Abstract Factory Motivação, propósito e aplicabilidade O padrão Abstract actory (fábrica abstrata) se propõe a oferecer uma interface para a criação de famílias de objetos, de forma a isolar a aplicação das classes concretamente utilizadas para a instanciação de tais objetos, sendo neste sentido idêntico ao padrão actory Method. A grande diferença é que uma fábrica abstrata pretende encapsular o mecanismo de seleção das famílias a serem utilizadas, acrescentando uma camada adicional de isolamento entre a aplicação e as classes utilizadas, sendo assim um mecanismo de criação abstrato mais sofisticado que o método fábrica. 06.pmd 466

63 Capítulo 6: Padrões de projeto Sistemas destinados a operarem em diferentes plataformas computacionais usualmente utilizam diferentes famílias de classes específicas dessas plataformas. Para que tais sistemas possuam a maior portabilidade possível, devemos evitar utilizar diretamente essas classes no código produzido, tornando-se necessário algum mecanismo transparente de seleção de uma família ou outra, conforme a situação. Aplicações que, de forma configurável, utilizam alternativamente diferentes toolkits para seu funcionamento, podem igualmente ser beneficiados dessa separação, permitindo sua melhor adaptação a diferentes ambientes. Esse padrão é aplicável às situações onde devemos não apenas isolar a criação de objetos dos locais de sua utilização, mas também quando são desejáveis configurações diferentes (em termos de famílias de objetos) ou ainda quando simplesmente se deseja fornecer apenas as interfaces dos objetos que serão usados. Por outro lado, tende a ser mais complexo que o padrão actory Method, pois exige uma hierarquia para as fábricas e não apenas para os produtos. Assim, a escolha entre esses padrões deve ser baseada na flexibilidade exigida. Estrutura, participantes e conseqüências A estrutura do padrão Abstract actory é muito semelhante ao actory Method, distinguindo-se pelo fato de existirem diversas implementações da fábrica, onde cada uma delas fornece produtos de uma mesma família. Os participantes identificados nesse padrão são: ± Interface IAbstract actory Oferece uma interface para obtenção de instâncias de fábricas ( actoryimpl), bem como especifica a interface para a obtenção dos produtos (ProductImpl). 467 ± Classe actoryimpl Implementação específica de uma fábrica que fornecerá diversos métodos capazes de fornecer uma família de produtos. ± Interface IProduct Especifica uma interface genérica para cada tipo de produto, independentemente da família a que pertencem. ± Classe ProductImpl Corresponde às implementações específicas dos produtos de cada família. Na igura 6.14, temos um diagrama de classes que ilustra o relacionamento entre os participantes desse padrão. EDITORA FUTURA 06.pmd 467

64 MAIS JAVA Figura 6.14 Estrutura do padrão AbstractFactory. A aplicação (ou cliente) que utilizará a fábrica abstrata deverá empregar a interface IAbstract actory para manipulá-la. Com relação aos objetos fornecidos, seu uso deverá ser realizado estritamente por meio das interfaces específicas de cada tipo. 468 Implementação e exemplo Usos conhecidos e padrões relacionados As fábricas abstratas são usualmente construídas com o uso de diversos métodos fábrica (padrão actory Method), tanto para a obtenção da instância adequada da fábrica como das instâncias dos produtos. Seu uso é muito adequado nas situações onde famílias distintas de produtos similares são necessárias, tais como famílias de componentes visuais para diferentes plataformas computacionais, daí a freqüente utilização desse padrão na estruturação de frameworks e toolkits. Usualmente as fábricas são implementadas como objetos Singleton (6.6.1), permitindo seu acesso global e evitando a possibilidade de duplicidade de fábricas e uso ineficiente de recursos do sistema Observer Motivação, propósito e aplicabilidade Nos casos onde existam um ou mais objetos interessados no estado de um outro objeto particular, esse padrão é adequado para descrever como estabelecer um relacionamento entre o objeto, cujo estado é observado, e qualquer número de objetos observadores, sem que estes tenham que perceber quando ocorre a mudança de estado do objeto observado. 06.pmd 468

65 Capítulo 6: Padrões de projeto O padrão Observer define uma relação de dependência de um para muitos (1:n) de modo que, quando um objeto tem seu estado modificado, seus observadores são notificados e atualizados automaticamente. Temos assim que o objeto observado torna-se responsável por avisar seus observadores da ocorrência de uma alteração, provocando sua atualização. Isso o torna aplicável às situações onde: ± O objeto observado não pode fazer considerações sobre quem são seus observadores nem seu número. ± É necessário separar os aspectos relacionados ao modelo de dados (contidos no objeto observado) e seu tratamento (objetos observadores). ± Desejamos variar independentemente tanto os observadores como os observados. Estrutura, participantes e conseqüências São quatro os participantes do padrão Observer: ± Interface IObserved Declara uma interface que permite a adição e a remoção de objetos observadores (que implementam a interface IObserver). Especifica operação de notificação dos observadores. Implicitamente requer uma lista de objetos observadores. 469 ± Classe ObservedImpl Armazena informações necessárias para os observadores (por exemplo, por meio de instâncias de uma classe State). Mantém uma lista com os observadores registrados. Notifica os observadores registrados quanto às mudanças no estado armazenado. ± Interface IObserver Especifica uma interface que deve ser implementada por classes (ObserverImpl) cujos objetos deverão ser notificados da alteração do estado de outros (ObservedImpl). ± Classe ObserverImpl Implementação específica das classes observadoras. Mantém uma referência para o objeto observado de forma que seu estado possa ser obtido quando ocorrer a notificação. O relacionamento entre esses participantes pode ser visto na igura EDITORA FUTURA 06.pmd 469

66 MAIS JAVA Figura 6.15 Estrutura do padrão Observer. 470 Conforme as anotações existentes no diagrama, podemos perceber que as implementações dos observadores (ObserverImpl) se registrarão na implementação do observado (ObservedImpl), mantendo uma referência para os mesmos. Tais objetos observados deverão manter uma lista de objetos observadores interessados nas mudanças de seu estado, notificando-os quando estas ocorrerem, acionando o método update(), especificado na interface IObserver, para que os mesmos sejam atualizados. A atualização, correspondente à obtenção do estado, bem como as demais operações que os observadores (ObserverImpl) executam sobre os objetos observados (ObservedImpl), utilizam apenas os métodos especificados na interface IObserved. Implementação e exemplo No Exemplo 6.35, temos uma aplicação Swing que demonstra como um botão (JButton) representa participante ObservedImpl (o elemento observado) do padrão Observer, permitindo o registro e a remoção de tantos observadores quantos desejados por meio de dois outros botões auxiliares posicionados na parte inferior da janela. Os observadores são implementados como uma classe independente (ButtonObserver) que faz o papel de ObserverImpl e que implementa a interface apropriada, isto é, ActionListener. Os botões auxiliares também são elementos observados por objetos instanciados a partir de classes anônimas declaradas na ocasião do registro dos listeners necessários. 06.pmd 470

67 Capítulo 6: Padrões de projeto // Observadores.java import java.awt.*; import java.awt.event.*; import javax.swing.*; public class Observadores extends J rame { private JButton b1, b2, b3; private JTextArea taresult; public Observadores() { super("observadores"); // instancia e organiza componentes JPanel p = new JPanel(); p.setborder(border actory.createetchedborder()); p.add(b1 = new JButton("Observado")); getcontentpane().add("north", p); JScrollPane sp = new JScrollPane(taResult = new JTextArea()); taresult.seteditable(false); getcontentpane().add("center", sp); p = new JPanel(new GridLayout(1, 3, 5, 5)); p.setborder(border actory.createetchedborder()); p.add(new JLabel("Observador")); p.add(b2 = new JButton("Adicionar")); p.add(b3 = new JButton("Remover")); getcontentpane().add("south", p); // registra listener anônimo (observador) p/ botão 2 b2.addactionlistener(new ActionListener(){ public void actionperformed(actionevent e) { b1.addactionlistener(new ButtonObserver(taResult)); taresult.append("observador adicionado.\n"); ); // registra listener anônimo (observador) p/ botão 2 b3.addactionlistener(new ActionListener(){ public void actionperformed(actionevent e) { ActionListener al[] = b1.getactionlisteners(); if (al.length>0) { b1.removeactionlistener(al[0]); taresult.append("observador removido.\n"); ); // outros ajustes setdefaultcloseoperation(j rame.exit_on_close); setsize(320, 240); 471 public static void main(string a[]) { new Observadores().show(); class ButtonObserver implements ActionListener { private static int control = 0; private int number; private JTextArea taresult; EDITORA FUTURA 06.pmd 471

68 MAIS JAVA public ButtonObserver(JTextArea ta) { number = ++control; taresult = ta; public void actionperformed(actionevent e) { taresult.append("observador #" + number + " notificado.\n"); Exemplo 6.35 Classe Observadores. Executando essa aplicação, poderemos notar que o botão Observado inicialmente não provoca nenhuma reação quando acionado, pois ainda não possui listener (observadores) registrados. Arbitrariamente podemos adicionar ou remover tantos listener (observadores) quanto desejados. A cada adição ou remoção uma mensagem indicativa é fornecida. Acionando-se o botão Observado, cada observador existente emitirá uma mensagem indicando sua notificação, permitindo que outras ações possam ser tomadas, demonstrando como o padrão Observer é usado no tratamento de eventos das aplicações AWT ou Swing. Na igura 6.16, podemos ver a aplicação Observadores em duas situações diferentes. 472 Figura 6.16 Aplicação Observadores. Usos conhecidos e padrões relacionados Como vimos, esse padrão é utilizado pelo modelo de eventos do Java (proposto a partir da versão 1.1) para estabelecer o relacionamento entre os componentes e as rotinas de tratamento dos eventos lançados por esses componentes. Os componentes são as implementações concretas dos elementos observados (participantes ObservedImpl) enquanto as classes onde residem as rotinas de tratamento dos eventos são os observadores (participantes ObserverImpl). As interfaces que devem ser implementadas para o processamento dos eventos (por exemplo, ActionListener, TextListener, ItemListener etc.) são as interfaces dos observadores (IObserver), enquanto a raiz da 06.pmd 472

Análise e Projeto Orientados por Objetos

Análise e Projeto Orientados por Objetos Análise e Projeto Orientados por Objetos Aula 05 Padrões GoF (Singleton e Iterator) Edirlei Soares de Lima Padrões GoF Criação: Abstract Factory Builder Factory Method Prototype

Leia mais

Mas o que é mesmo Padrão de Projeto?

Mas o que é mesmo Padrão de Projeto? Mas o que é mesmo Padrão de Projeto? Um Padrão de Projeto descreve uma solução comprovada para um problema recorrente e conhecido no desenvolvimento de software orientado a objetos. Mas afinal, porque

Leia mais

Padrões de Projeto. Padrões de Projeto. Além dos 23 Padrões GoF. Os 23 Padrões de Projeto. Documentação de um Padrão. Classificação dos Padrões

Padrões de Projeto. Padrões de Projeto. Além dos 23 Padrões GoF. Os 23 Padrões de Projeto. Documentação de um Padrão. Classificação dos Padrões DCC / ICEx / UFMG Padrões de Projeto Padrões de Projeto Eduardo Figueiredo http://www.dcc.ufmg.br/~figueiredo Um padrão é uma descrição do problema e a essência da sua solução Documenta boas soluções para

Leia mais

Tópicos Avançados em Linguagem de Programação. Padrões de Software. Prof. Alexandre Vidal DEINF-UFMA. Ciência da Computação

Tópicos Avançados em Linguagem de Programação. Padrões de Software. Prof. Alexandre Vidal DEINF-UFMA. Ciência da Computação Tópicos Avançados em Linguagem de Programação Prof. Alexandre Vidal DEINF-UFMA Ciência da Computação Patterns (padrões) Compõem uma disciplina da Engenharia de Software voltada para a resolução de problemas

Leia mais

Roni Fabio Banaszewski UTFPR Universidade Tecnológica Federal do Paraná

Roni Fabio Banaszewski UTFPR Universidade Tecnológica Federal do Paraná Roni Fabio Banaszewski UTFPR Universidade Tecnológica Federal do Paraná Reuso Motivações para reutilização de software Aspecto econômico Produtividade Time to market Qualidade Utilização de artefatos (código,

Leia mais

Módulo III Padrões GOF: Iterator

Módulo III Padrões GOF: Iterator Módulo III Padrões GOF: Iterator Professores Eduardo Bezerra edubezerra@gmail.com Ismael H F Santos ismael@tecgraf.puc-rio.br April 05 Prof. Ismael H. F. Santos - ismael@tecgraf.puc-rio.br 1 Ementa Padrões

Leia mais

Tópicos da Aula. POO e Padrões de Projetos. Considere três classes... Reuso de Classes. Locadora de DVD. Sistema Acadêmico

Tópicos da Aula. POO e Padrões de Projetos. Considere três classes... Reuso de Classes. Locadora de DVD. Sistema Acadêmico Reuso de Software Aula 03 Tópicos da Aula POO e Padrões de Projetos Eduardo Figueiredo http://www.dcc.ufmg.br/~figueiredo reuso.software@gmail.com 12 Março 2012 Programação orientada a objetos Reuso de

Leia mais

Módulo I Princípios e Padrões de Projeto de SW em Java

Módulo I Princípios e Padrões de Projeto de SW em Java Módulo I Princípios e Padrões de Projeto de SW em Java Professores Eduardo Bezerra edubezerra@gmail.com Ismael H F Santos ismael@tecgraf.puc-rio.br April 05 Prof. Ismael H. F. Santos - ismael@tecgraf.puc-rio.br

Leia mais

Classes e Objetos. Sintaxe de classe em Java

Classes e Objetos. Sintaxe de classe em Java Classes e Objetos Classes e Objetos A Programação Orientada a Objetos (POO) é uma técnica de programação que se baseia na construção de classes e utilização de objetos. Os objetos são formados por dados

Leia mais

Padrões de Projeto. Parte 1. Prof. Fellipe Aleixo

Padrões de Projeto. Parte 1. Prof. Fellipe Aleixo Padrões de Projeto Parte 1 Prof. Fellipe Aleixo (fellipe.aleixo@ifrn.edu.br) Padrões de Projeto de Software OO Também conhecidos como Padrões de Projeto de Software OO ou simplesmente como Padrões A Inspiração

Leia mais

INF1636 PROGRAMAÇÃO ORIENTADA A OBJETOS

INF1636 PROGRAMAÇÃO ORIENTADA A OBJETOS INF1636 PROGRAMAÇÃO ORIENTADA A OBJETOS Departamento de Informática PUC-Rio Ivan Mathias Filho ivan@inf.puc-rio.br Programa Capítulo 17 Padrões de Design Singleton Facade Factory Method Observer Strategy

Leia mais

Padrões de Projeto de Software Orientado a Objetos

Padrões de Projeto de Software Orientado a Objetos Padrões de Projeto de Software Orientado a Objetos Ricardo Argenton Ramos [Baseado nos slides do professor Fabio Kon - USP] 1 Padrões de Projeto de Software OO Também conhecidos como Padrões de Desenho

Leia mais

Padrões contexto problema solução

Padrões contexto problema solução Padrões Padrões são soluções para problemas específicos que ocorrem de forma recorrente em um determinado contexto que foram identificados a partir da experiência coletiva de desenvolvedores de software.

Leia mais

Padrões de Projeto de Software

Padrões de Projeto de Software Padrões de Projeto de Software Introdução Paulo Gomide Departamento de Ciência da Computação Universidade de Itaúna Motivação Introdução Por que Padrões? Por que Padrões de Projeto? O que é um Padrão de

Leia mais

Orientação a Objetos AULA 09

Orientação a Objetos AULA 09 Orientação a Objetos AULA 09 Prof. Fabrício Martins Mendonça Conteúdo da Aula ü Coleções ü Coleções lista de objetos ü Coleções conjuntos 2 Coleções Podemos armazenar vários objetos em um array e este

Leia mais

SISMO - Sistemas e Mobilidade Departamento de Informática / UFMA. Junho de 2008

SISMO - Sistemas e Mobilidade  Departamento de Informática / UFMA. Junho de 2008 Introdução SISMO - Sistemas e Mobilidade http://www.sismo.deinf.ufma.br Departamento de Informática / UFMA Junho de 2008 Compõem uma disciplina da Engenharia de Software voltada para a resolução de problemas

Leia mais

INF011 Padrões de Projeto Introdução

INF011 Padrões de Projeto Introdução INF011 Padrões de Projeto 01 - Introdução Sandro Santos Andrade sandroandrade@ifba.edu.br Instituto Federal de Educação, Ciência e Tecnologia da Bahia Departamento de Tecnologia Eletro-Eletrônica Graduação

Leia mais

Singleton. Como a maioria dos programadores organizaria o código para acessar informação de configuração? Eis um exemplo:

Singleton. Como a maioria dos programadores organizaria o código para acessar informação de configuração? Eis um exemplo: Introdução Como a maioria dos programadores organizaria o código para acessar informação de configuração? Eis um exemplo: public class Config { public static final String DEFAULT_READ_COMMUNITY_NAME =

Leia mais

Singleton e Adapter. Professor: Nazareno Andrade (baseado no material de Hyggo Almeida e Jacques Sauvé)

Singleton e Adapter. Professor: Nazareno Andrade (baseado no material de Hyggo Almeida e Jacques Sauvé) e Adapter Professor: Nazareno Andrade (baseado no material de Hyggo Almeida e Jacques Sauvé) O que vimos na última aula? Factory Method Abstract Factory 2 O que veremos hoje? (padrão de criaçã) Adapter

Leia mais

PADRÕES DE PROJETO: DESIGN PATTERNS

PADRÕES DE PROJETO: DESIGN PATTERNS PADRÕES DE PROJETO: DESIGN PATTERNS Jaime William Dias 1, Danilo Venturini 1, William Macxuel Muniz 1, Rodrigo Niehues Chagas 1 1 Universidade Paranaense (UNIPAR) Paranavaí PR Brasil danilo_tr98@hotmail.com,

Leia mais

AULA 02. OBJETIVO: Características da Linguagem Orientada a Objetos.

AULA 02. OBJETIVO: Características da Linguagem Orientada a Objetos. AULA 02 OBJETIVO: Características da Linguagem Orientada a Objetos. HABILIDADES TRABALHADAS: Comparação das características das linguagens orientadas a objetos frente às linguagens estruturadas. Conhecimentos

Leia mais

LEIC-T LERC MEIC-T 2011/2012 1º Semestre Programação com Objetos 2012/01/07 11h00m 3/10

LEIC-T LERC MEIC-T 2011/2012 1º Semestre Programação com Objetos 2012/01/07 11h00m 3/10 2/10 1.1. (1.5 val.) Os mecanismos de herança entre classes e de composição de objetos são, por vezes, apresentados como alternativos, face à disponibilização de funcionalidade a uma classe. Compare-os,

Leia mais

Programação Orientada a Objetos

Programação Orientada a Objetos Programação Orientada a Objetos Prof. Kléber de Oliveira Andrade pdjkleber@gmail.com Coleções, Propriedades, Resources e Strings (Parte 2) Coleções É comum usarmos um objeto que armazena vários outros

Leia mais

Projeto de software Estrutura do software e arquitetura SWEBOK

Projeto de software Estrutura do software e arquitetura SWEBOK Projeto de software Estrutura do software e arquitetura SWEBOK SWEBOK Design Patterns Maneira testada ou documentada de alcançar um objetivo qualquer Padrões são comuns em várias áreas da engenharia Design

Leia mais

Linguagem de Programação III

Linguagem de Programação III Linguagem de Programação III Aula-7 Reutilização de Classes Prof. Esbel Tomás Valero Orellana Até Aqui Introdução a POO e sua implementação em Java Atributos, métodos e encapsulamento dos mesmos Trabalhando

Leia mais

Engenharia de Software

Engenharia de Software Engenharia de Software Projeto e Implementação Padrões de Projeto Msc. Carlos Mar 04/2014 REVISÃO: ORIENTAÇÃO A OBJETOS Msc. Carlos Mar - Abr/2014 Conceitos Fundamentais Classe Objeto Atributos Métodos

Leia mais

PROGRAMAÇÃO ORIENTADA A OBJETOS II -TÉCNICAS DE OO. Prof. Angelo Augusto Frozza, M.Sc.

PROGRAMAÇÃO ORIENTADA A OBJETOS II -TÉCNICAS DE OO. Prof. Angelo Augusto Frozza, M.Sc. PROGRAMAÇÃO ORIENTADA A OBJETOS II -TÉCNICAS DE OO Prof. Angelo Augusto Frozza, M.Sc. frozza@ifc-camboriu.edu.br ROTEIRO 4. Técnicas de Orientação a Objetos Classes e objetos Herança Métodos Subscritos

Leia mais

Programação Orientada a Objetos. Padrões Estruturais

Programação Orientada a Objetos. Padrões Estruturais Programação Orientada a Objetos Padrões Estruturais Cristiano Lehrer, M.Sc. Classificação dos Padrões de Projeto Propósito o que o padrão faz: Padrões de criação: abstraem o processo de criação de objetos

Leia mais

Paradigmas de Linguagens de Programação. Suporte para Programação Orientada a Objeto

Paradigmas de Linguagens de Programação. Suporte para Programação Orientada a Objeto Suporte para Programação Orientada a Objeto Cristiano Lehrer Categoria das Linguagens que Suportam POO Suporte a POO acrescentado a uma linguagem já existente: C++ (também suporta programação procedural

Leia mais

Programação Orientada a Objectos - P. Prata, P. Fazendeiro

Programação Orientada a Objectos - P. Prata, P. Fazendeiro Programação Orientada a Objetos 1.1 - Perspectiva histórica: Conceitos A evolução das linguagens de programação tem-se feito na procura de ferramentas: -cada vez mais próximas da percepção humana - e que

Leia mais

Paginador. Intenção. Motivação

Paginador. Intenção. Motivação Paginador Intenção Fornecer um mecanismo que permita o acesso a um conjunto de objetos por partes, definidas como páginas, mantendo o controle da navegação dos objetos na página corrente. Motivação Vamos

Leia mais

Televisao tamanho tela emitirsom. conectarperifericos

Televisao tamanho tela emitirsom. conectarperifericos 1 - Introdução a Programação Orientada a Objeto Para tentar solucionar o problema do baixo reaproveitamento de código, surgiu a idéia da Programação Orientada a Objeto (POO). A POO não é nova, sua formulação

Leia mais

Introdução à Análise e Projeto de Sistemas

Introdução à Análise e Projeto de Sistemas Introdução à I. O Que vamos fazer na Disciplina? Saber uma linguagem de programação orientada a objeto (OO) não é suficiente para criar sistemas OO Tem que saber Análise e Projeto OO (APOO) Isto é, Análise

Leia mais

Ciência da Computação. Análise e Projeto Orientado a Objetos UML. Anderson Belgamo

Ciência da Computação. Análise e Projeto Orientado a Objetos UML. Anderson Belgamo Ciência da Computação Análise e Projeto Orientado a Objetos UML Anderson Belgamo 1 Evolução do Software O rápido crescimento da capacidade computacional das máquinas resultou na demanda por sistemas de

Leia mais

Coleções. João Paulo Q. dos Santos

Coleções. João Paulo Q. dos Santos Coleções João Paulo Q. dos Santos joao.queiroz@ifrn.edu.br Roteiro Conceitos sobre coleções; Tipos de coleções; Como são classificadas; Exemplos. 04/02/14 2 Coleções Classes e interfaces do pacote java.util

Leia mais

Análise e Projeto. Padrões de Análise, Arquitetura e Projeto

Análise e Projeto. Padrões de Análise, Arquitetura e Projeto Análise e Projeto Padrões de Análise, Arquitetura e Projeto 33 Padrões de Arquitetura Padrões Nome do padrão Problema: quando aplicar o padrão? Descreve o problema e seu contexto. Solução: elementos que

Leia mais

ESTUDO DO PADRÃO DE PROJETO OBSERVER NO DESENVOLVIMENTO DE SOFTWARES UTILIZANDO A ARQUITETURA MVC RESUMO

ESTUDO DO PADRÃO DE PROJETO OBSERVER NO DESENVOLVIMENTO DE SOFTWARES UTILIZANDO A ARQUITETURA MVC RESUMO Mostra Nacional de Iniciação Científica e Tecnológica Interdisciplinar III MICTI Fórum Nacional de Iniciação Científica no Ensino Médio e Técnico - I FONAIC-EMT Camboriú, SC, 22, 23 e 24 de abril de 2009

Leia mais

Padrão Comportamental: Paginador

Padrão Comportamental: Paginador Padrão Comportamental: Paginador Wellington Pinheiro Paulo Fernando Intenção Fornecer um mecanismo que permita o acesso a um conjunto de objetos por partes, definidas como páginas, mantendo o controle

Leia mais

API e Coleções Java. Sérgio Luiz Ruivace Cerqueira

API e Coleções Java. Sérgio Luiz Ruivace Cerqueira API e Coleções Java Sérgio Luiz Ruivace Cerqueira sergioruivace@gmail.com Java API Introdução API Endereço http://download.oracle.com/javase/6/docs/api/ API - Descrição API - Resumo API - Detalhes Coleções

Leia mais

Universidade Federal de Itajubá Instituto de Engenharia de Sistemas e Tecnologias da Informação-IESTI CCO002 Engenharia de Software

Universidade Federal de Itajubá Instituto de Engenharia de Sistemas e Tecnologias da Informação-IESTI CCO002 Engenharia de Software UNIFEI Disciplina Professor Universidade Federal de Itajubá Instituto de Engenharia de Sistemas e Tecnologias da Informação-IESTI CCO002 Engenharia de Software Enzo Seraphim 1 Padrões de Construção A maneira

Leia mais

Notas de Aula 03: Introdução a Orientação a Objetos e a UML

Notas de Aula 03: Introdução a Orientação a Objetos e a UML Notas de Aula 03: Introdução a Orientação a Objetos e a UML Objetivos da aula: Introduzir os conceitos da Orientação à Objetos (O.O) Introduzir os conceitos da UML Relacionar os processos às ferramentas

Leia mais

UNIVERSIDADE FEDERAL DE SANTA MARIA CENTRO DE TECNOLOGIA AULA 15 PROFª BRUNO CALEGARO

UNIVERSIDADE FEDERAL DE SANTA MARIA CENTRO DE TECNOLOGIA AULA 15 PROFª BRUNO CALEGARO UNIVERSIDADE FEDERAL DE SANTA MARIA CENTRO DE TECNOLOGIA AULA 15 PROFª BRUNO CALEGARO Santa Maria, 08 de Novembro de 2013. Contextualização Nas próximas aula iremos começar a modelar e projetar sistemas

Leia mais

Introdução aos Padrões de Projeto. Sylvio Barbon Jr

Introdução aos Padrões de Projeto. Sylvio Barbon Jr Introdução aos Padrões de Projeto Sylvio Barbon Jr 25 février 2016 Introdução Disciplina Engenharia de Software : São Tratados principalmente os tesmas : Metodologia : No desenvolvimento

Leia mais

Agenda da Aula. Arquitetura de Software e Padrões Arquiteturais. Elementos de um Padrão. Arquitetura de Software. Arquitetura de Software

Agenda da Aula. Arquitetura de Software e Padrões Arquiteturais. Elementos de um Padrão. Arquitetura de Software. Arquitetura de Software Reuso de Software Aula 04 Agenda da Aula Arquitetura de Software e Eduardo Figueiredo http://www.dcc.ufmg.br/~figueiredo reuso.software@gmail.com 14 Março 2012 Arquitetura de Software Padrões arquiteturais

Leia mais

Introdução. à UML. Histórico (cont.) Histórico Definição Benefícios Notação Diagrama de Classes Diagramas de Interação Conclusões Revisão

Introdução. à UML. Histórico (cont.) Histórico Definição Benefícios Notação Diagrama de Classes Diagramas de Interação Conclusões Revisão Sumário Introdução à UML BSI Bacharelado em Sistemas de Informação LOO Linguagens Orientadas a Objetos Humberto Mossri de Almeida hmossri_cursos@yahoo.com.br Marcelo Nassau Malta nassau_cursos@yahoo.com.br

Leia mais

Iteradores. Iteradores. Isabel Harb Manssour. Roteiro. Coleções

Iteradores. Iteradores. Isabel Harb Manssour. Roteiro. Coleções Implementação de Genéricos, Iteradores Isabel Harb Manssour Porto Alegre, maio de 2006 Roteiro Implementação de Genéricos Coleções Conceito de Genérico Implementação Iteradores Conceito Utilização ForEach

Leia mais

Computação II Orientação a Objetos

Computação II Orientação a Objetos Computação II Orientação a Objetos Fabio Mascarenhas - 2016.2 http://www.dcc.ufrj.br/~fabiom/java Revisão Classes e Objetos Classes são uma das unidades básicas de um programa Java Usamos as classes para

Leia mais

Universidade Federal de Uberlândia Faculdade de Computação Prof. Fabiano Dorça. Introdução. Padrões de projeto

Universidade Federal de Uberlândia Faculdade de Computação Prof. Fabiano Dorça. Introdução. Padrões de projeto Universidade Federal de Uberlândia Faculdade de Computação Prof. Fabiano Dorça Introdução Padrões de projeto Algumas definições... Um padrão de projeto (design pattern) é uma solução geral reutilizável

Leia mais

INF011 Padrões de Projeto. 11 Composite

INF011 Padrões de Projeto. 11 Composite INF011 Padrões de Projeto 11 Composite Sandro Santos Andrade sandroandrade@ifba.edu.br Instituto Federal de Educação, Ciência e Tecnologia da Bahia Departamento de Tecnologia Eletro-Eletrônica Graduação

Leia mais

3 Uma Abordagem Orientada a Aspectos para o Desenvolvimento de Frameworks

3 Uma Abordagem Orientada a Aspectos para o Desenvolvimento de Frameworks 48 3 Uma Abordagem Orientada a Aspectos para o Desenvolvimento de Frameworks Este capítulo apresenta uma visão geral da contribuição principal deste trabalho: uma abordagem orientada a aspectos para o

Leia mais

Padrões de Design Orientado a Objetos Design Patterns. Jorge H. C. Fernandes DI-UFPE, Junho de 1999

Padrões de Design Orientado a Objetos Design Patterns. Jorge H. C. Fernandes DI-UFPE, Junho de 1999 Padrões de Design Orientado a Objetos Design Patterns Jorge H. C. Fernandes DI-UFPE, Junho de 1999 Padrões de Design Bibliografia Design Patterns: Elements of Reusable Object- Oriented Software. Gamma,

Leia mais

PROJETO DE DADOS PROJETO ARQUITETURAL BÁSICO. Projeto de Programas PPR0001

PROJETO DE DADOS PROJETO ARQUITETURAL BÁSICO. Projeto de Programas PPR0001 1 PROJETO DE DADOS PROJETO ARQUITETURAL BÁSICO Projeto de Programas PPR0001 2 Atividades Envolvidas Preliminar Realizar a organização dos dados considerando a tecnologia que será utilizada em módulos (exemplo:

Leia mais

UML (Unified Modelling Language)

UML (Unified Modelling Language) UML (Unified Modelling Language) Curso de Especialização DEINF - UFMA Desenvolvimento Orientado a Objetos Prof. Geraldo Braz Junior Referências: Booch, G. et al. The Unified Modeling Language User Guide

Leia mais

Padrão de projeto de software

Padrão de projeto de software Padrão de projeto de software Paulo Venancio Lopes e Daniel Sguillaro Nome Roupa Suja Se Lava Em Casa. Intenção Dar maior capacidade e flexibilidade ao conceito de entidade (no contexto de persitência

Leia mais

PROJETO ARQUITETURAL PARTE II: PADRÕES DE PROJETO. Projeto de Programas PPR0001

PROJETO ARQUITETURAL PARTE II: PADRÕES DE PROJETO. Projeto de Programas PPR0001 PROJETO ARQUITETURAL PARTE II: PADRÕES DE PROJETO Projeto de Programas PPR0001 QUALIDADE DO PROJETO 2 3 Qualidade do Projeto de Software Modularidade: gerar particionamento em elementos que executam funções

Leia mais

3 Tecnologias Relacionadas

3 Tecnologias Relacionadas Tecnologias Relacionadas 31 3 Tecnologias Relacionadas O objetivo deste capítulo é apresentar um resumo de cada tecnologia relacionada ao processo proposto nesta dissertação, mostrando suas principais

Leia mais

Figura 1. Estrutura do agente de software.

Figura 1. Estrutura do agente de software. 24 2 Conceitos Básicos A engenharia de software baseada em agentes é uma área emergente cujo objetivo é oferecer suporte ao desenvolvimento de sistemas multi-agentes (Garcia et al., 2003; Jennings & Wooldridge,

Leia mais

Visões Arquiteturais. Visões Arquiteturais

Visões Arquiteturais. Visões Arquiteturais Visões Arquiteturais Separar diferentes aspectos em visões separadas com o objetivo de gerenciar complexidade. Cada visão descreve diferentes conceitos da Engenharia. Visões permitem reduzir a quantidade

Leia mais

Recapitulando. Construtores: (Overload assinatura) public Circle() {...} public Circle(double x, double y, double r) {... }

Recapitulando. Construtores: (Overload assinatura) public Circle() {...} public Circle(double x, double y, double r) {... } Recapitulando Orientação a objetos: programas organizados em torno da definição de classes, instanciação de objetos e troca de mensagens. Declaração de variáveis de referencia: Circle c; Criação/instanciação

Leia mais

Conceitos de Programação Orientada a Objetos

Conceitos de Programação Orientada a Objetos Conceitos de Programação Orientada a Objetos Tatyana Bitencourt Com as técnicas de orientação a objeto, é possível obter resultados considerados impossíveis pensando de maneira estruturada. Como Java não

Leia mais

Herança. Prof. Fernando V. Paulovich 23 de agosto de 2010

Herança. Prof. Fernando V. Paulovich  23 de agosto de 2010 Herança SCC0604 - Programação Orientada a Objetos Prof. Fernando V. Paulovich http://www.icmc.usp.br/~paulovic paulovic@icmc.usp.br Instituto de Ciências Matemáticas e de Computação(ICMC) Universidade

Leia mais

Programação Orientada a Objetos. Professor: André Luis Meneses Silva br.geocities.com/programacao2ufs

Programação Orientada a Objetos. Professor: André Luis Meneses Silva br.geocities.com/programacao2ufs Programação Orientada a Objetos Professor: André Luis Meneses Silva andreluis.ms@gmail.com br.geocities.com/programacao2ufs [ Conteúdo ] Objeto Mensagens Classe Encapsulamento Visibilidade Membros de Instância

Leia mais

Linguagem de Programação II Programação Orientada a Objetos. Orientação a Objetos

Linguagem de Programação II Programação Orientada a Objetos. Orientação a Objetos Linguagem de Programação II Programação Orientada a Objetos Orientação a Objetos Prof. Alessandro Borges 2 Tópicos Introdução à Programação Orientada a Objetos Conceitos Objetivos Classes e Objetos Atributos

Leia mais

Classes o Objetos. Classes, objetos, métodos e variáveis de instância

Classes o Objetos. Classes, objetos, métodos e variáveis de instância Classes o Objetos Um recurso comum de cada aplicativo feito até agora é que todas as instruções que realizavam tarefas localizavam-se no método main. Se você tornar parte de uma equipe de desenvolvimento

Leia mais

Modelo do Mundo Real. Abstração. Interpretação

Modelo do Mundo Real. Abstração. Interpretação Modelo do Mundo Real Mundo Real Abstração Interpretação Sistema de Software Modelo Algoritmo Abstração: O modelo precisa capturar apenas as características do mundo real que são importantes para o sistema

Leia mais

Desenho e documentação de arquitectura de software e de aplicações empresariais

Desenho e documentação de arquitectura de software e de aplicações empresariais Desenho e documentação de arquitectura de software e de aplicações empresariais João Pascoal Faria Laboratório de Engenharia de Software 10 de Novembro de 2003 1 Definição de arquitectura de software Arquitectura

Leia mais

Universidade Federal de Uberlândia Faculdade de Computação Programação Orientada a Objetos II Prof. Fabiano Dorça. Padrão Observer (Observador)

Universidade Federal de Uberlândia Faculdade de Computação Programação Orientada a Objetos II Prof. Fabiano Dorça. Padrão Observer (Observador) Universidade Federal de Uberlândia Faculdade de Computação Programação Orientada a Objetos II Prof. Fabiano Dorça Problema: Definir uma dependência um-para-muitos entre objetos, de forma quando o estado

Leia mais

UML e seus diagramas

UML e seus diagramas UML e seus diagramas A UML Unified Modeling Language (Linguagem de Modelagem Unificada), como o próprio nome já diz, é uma linguagem para modelagem de objetos do mundo real, usada para especificar, construir,

Leia mais

Desenvolvimento e Projeto de Aplicações Web

Desenvolvimento e Projeto de Aplicações Web Desenvolvimento e Projeto de Aplicações Web cecafac@gmail.com Coleções Conteúdo 1 Introdução Desde a versão 1.2 do JDK, a plataforma J2SE inclui um framework de coleções (Collections) Uma coleção é um

Leia mais

O Pronome CREATOR 4.1. O objeto criador do objeto corrente

O Pronome CREATOR 4.1. O objeto criador do objeto corrente 4 O Pronome CREATOR Neste capítulo, é explorado o pronome CREATOR. Na Seção 4.1, a relação entre o objeto corrente e seu criador é explicada. Na Seção 4.2, são mostradas as transformações de código necessárias

Leia mais

Programação com Objectos 2º Teste Tipo 1º Semestre (120 minutos)

Programação com Objectos 2º Teste Tipo 1º Semestre (120 minutos) 1/8 Programação com Objectos 2º Teste Tipo 1º Semestre (120 minutos) Nome: Primeira Parte (7 valores) PERGUNTA NOTA 1.1.1 1.1.2 1.1.3 1.2 1.3 1.4 Segunda Parte (3 valores) PERGUNTA RESPOSTA 2.1 2.2 2.3

Leia mais

Agenda da Aula. Reuso de Software. Tipos de Reuso. Potenciais Problemas. Vantagens de Reuso. Introdução a Reuso de Software

Agenda da Aula. Reuso de Software. Tipos de Reuso. Potenciais Problemas. Vantagens de Reuso. Introdução a Reuso de Software Reuso de Software Aula 02 Agenda da Aula Introdução a Reuso de Software Eduardo Figueiredo http://www.dcc.ufmg.br/~figueiredo reuso.software@gmail.com Introdução a Reuso de Software Abordagens de Reuso

Leia mais

Os princípios do desenho orientado a objetos

Os princípios do desenho orientado a objetos Os princípios do desenho orientado a objetos Os princípios do desenho orientado a objetos Encapsulamento e congeneridade Domínios, grau de dependência e coesão Os perigos da herança e do polimorfismo Encapsulamento

Leia mais

Creational Patterns Factory method

Creational Patterns Factory method Objetivo do Factory method é definir qual será a subclasse que utilizada um cliente. Permite que o sistema funcione sem o conhecimento prévio das subclasses. Assim um framework pode ser construído apenas

Leia mais

A modelagem é tida como a parte central de todas as atividades para a construção de um bom sistema, com ela podemos:

A modelagem é tida como a parte central de todas as atividades para a construção de um bom sistema, com ela podemos: Módulo 6 Análise Orientada a Objeto É interessante observar como a análise orientada a objeto utiliza conceitos que aprendemos há muito tempo: objetos, atributos, classes, membros, todos e partes. Só não

Leia mais

INF1013 MODELAGEM DE SOFTWARE

INF1013 MODELAGEM DE SOFTWARE INF1013 MODELAGEM DE SOFTWARE Departamento de Informática PUC-Rio Ivan Mathias Filho ivan@inf.puc-rio.br Programa Capítulo 1 O Paradigma Orientado a Objetos A Linguagem UML Descrição da Arquitetura 1 Programa

Leia mais

Desenvolvimento de Sistemas Orientados a Objetos com UML UP/RUP: Projeto

Desenvolvimento de Sistemas Orientados a Objetos com UML UP/RUP: Projeto Desenvolvimento de Sistemas Orientados a Objetos com UML UP/RUP: Projeto Engenharia de Software I Informática 2006 Profa. Dra. Itana Gimenes RUP: Projeto Artefatos Modelo de Projeto: Lista de classes de

Leia mais

Arquitectura de Sistemas de Software

Arquitectura de Sistemas de Software Arquitectura de Sistemas de Software Ademar Aguiar www.fe.up.pt/~aaguiar ademar.aguiar@fe.up.pt Arquitectura de Sistemas de Software, LEIC/MEI, 2003/2004 1 Arquitectar... Arquitectar uma pequena cabana

Leia mais

Padrões de Projeto de Software

Padrões de Projeto de Software Padrões de Projeto de Software Luiz Leão luizleao@gmail.com http://www.luizleao.com Introdução O que é? Como descrever? Principais Padrões de Projetos Unidade 2 Padrões GoF PADRÕES CRIAÇÃO Abstract Factory

Leia mais

Padrões de Projeto de Software

Padrões de Projeto de Software Padrões de Projeto de Software Lista de Exercícios AV1 01 Luiz Leão luizleao@gmail.com http://www.luizleao.com Questão 1 Dentre as alternativas abaixo identifique a que NÃO define uma situação em que deve

Leia mais

Collections Framework

Collections Framework Collections Framework 1 Arrays p Manipular array é bastante trabalhoso. p Dificuldades aparecem em diversos momentos: n não podemos redimensionar um array em Java; n é impossível buscar diretamente por

Leia mais

Introdução ao Java. Prof. Herbert Rausch Fernandes

Introdução ao Java. Prof. Herbert Rausch Fernandes Introdução ao Java Prof. Herbert Rausch Fernandes Orientação a Objetos Programação Orientada por Objetos: é a construção de sistemas de software como uma coleção estruturada de implementações de tipos

Leia mais

MANUAL PARA DESENVOLVIMENTO DE SOFTWARE TRABALHO DE CONCLUSAO DE CURSO EM SISTEMAS DE INFORMAÇÃO

MANUAL PARA DESENVOLVIMENTO DE SOFTWARE TRABALHO DE CONCLUSAO DE CURSO EM SISTEMAS DE INFORMAÇÃO MANUAL PARA DESENVOLVIMENTO DE SOFTWARE TRABALHO DE CONCLUSAO DE CURSO EM SISTEMAS DE INFORMAÇÃO Sumário PREFÁCIO...3 MODELO DA DOCUMENTAÇÃO...3 1. INTRODUÇÃO AO DOCUMENTO...3 1.1. Tema...3 2. DESCRIÇÃO

Leia mais

Técnicas para Reutilização de Software

Técnicas para Reutilização de Software DCC / ICEx / UFMG Técnicas para Reutilização de Software Eduardo Figueiredo http://www.dcc.ufmg.br/~figueiredo Panorama de Reutilização Frameworks Padrões de projeto Aplicações configuráveis Padrões de

Leia mais

Linguagens de Programação Aula 12

Linguagens de Programação Aula 12 Linguagens de Programação Aula 12 Celso Olivete Júnior olivete@fct.unesp.br Na aula passada Implementando subprogramas 2 Na aula de hoje Suporte para a programação orientada a objetos 3 Roteiro Introdução

Leia mais

Aula 5 POO 1 Encapsulamento. Profa. Elaine Faria UFU

Aula 5 POO 1 Encapsulamento. Profa. Elaine Faria UFU Aula 5 POO 1 Encapsulamento Profa. Elaine Faria UFU - 2019 Sobre o Material Agradecimentos Aos professores José Gustavo e Fabiano, por gentilmente terem cedido seus materiais. Os slides consistem de adaptações

Leia mais

Abstract Factory. Prover uma interface para criar uma família de objetos relacionados ou dependentes sem especificar suas classes concretas

Abstract Factory. Prover uma interface para criar uma família de objetos relacionados ou dependentes sem especificar suas classes concretas Objetivo Prover uma interface para criar uma família de objetos relacionados ou dependentes sem especificar suas classes concretas Também chamado de Kit Resumo Parece semelhante ao padrão Factory Method,

Leia mais

Modulo I Princípios e Padrões de Projeto de SW em Java

Modulo I Princípios e Padrões de Projeto de SW em Java Modulo I Princípios e Padrões de Projeto de SW em Java Professores Eduardo Bezerra edubezerra@gmail.com Ismael H F Santos ismael@tecgraf.puc-rio.br April 05 Prof. Ismael H. F. Santos - ismael@tecgraf.puc-rio.br

Leia mais

Introdução Diagrama de Classes Diagrama de Seqüência Diagrama de Atividades. Diagramas UML. Classe, Seqüência e Atividades. Marcio E. F.

Introdução Diagrama de Classes Diagrama de Seqüência Diagrama de Atividades. Diagramas UML. Classe, Seqüência e Atividades. Marcio E. F. Diagramas UML Classe, Seqüência e Atividades Marcio E. F. Maia Disciplina: Engenharia de Software Professora: Rossana M. C. Andrade Curso: Ciências da Computação Universidade Federal do Ceará 15 de maio

Leia mais

Conceitos, Arquitetura e Design

Conceitos, Arquitetura e Design capítulo 1 Conceitos, Arquitetura e Design 1.1 O que são os serviços de diretórios? Segundo a Wikipédia: Um serviço de diretório é um software que armazena e organiza informações sobre os recursos e os

Leia mais

Engenharia de Software II e III - Material para estudo Diagrama de Classe

Engenharia de Software II e III - Material para estudo Diagrama de Classe 1-Orientação a Objetos ANÁLISE ESTRUTURADA X ANÁLISE O.O. Enfoque Tradicional: Conjunto de programas que executam processos sobre dados. Enfoque Baseado em Objetos: Conjunto de coisas que tem características

Leia mais

UML UNIFIED MODELING LANGUAGE LINGUAGEM DE MODELAGEM UNIFICADA

UML UNIFIED MODELING LANGUAGE LINGUAGEM DE MODELAGEM UNIFICADA UML UNIFIED MODELING LANGUAGE LINGUAGEM DE MODELAGEM UNIFICADA UML - Introdução Não é uma linguagem de programação É uma linguagem de modelagem e projeto É uma linguagem padrão para modelagem orientada

Leia mais

Computação II Orientação a Objetos

Computação II Orientação a Objetos Computação II Orientação a Objetos Fabio Mascarenhas - 2014.1 http://www.dcc.ufrj.br/~fabiom/java Breakout Componentes do Breakout Bola Raquete Tijolos Paredes Score Nem todos vão precisar de classes próprias

Leia mais

UML (Linguagem Modelagem Unificada) João Paulo Q. dos Santos

UML (Linguagem Modelagem Unificada) João Paulo Q. dos Santos UML (Linguagem Modelagem Unificada) João Paulo Q. dos Santos joao.queiroz@ifrn.edu.br Roteiro A importância da UML para projetar sistemas. Principais características do diagrama de classes e de sequência.

Leia mais

Introdução a Teste de Software

Introdução a Teste de Software Universidade Católica de Pelotas Tecnólogo em Análise e Desenvolvimento de Sistemas Disciplina de Qualidade de Software Introdução a Teste de Software Prof. Luthiano Venecian 1 Conceitos Teste de software

Leia mais

Apêndice A. Alguns construtores e métodos importantes e úteis da classe Vector são:

Apêndice A. Alguns construtores e métodos importantes e úteis da classe Vector são: Apêndice A Classe Vector A classe Vector permite a representação de um vetor de dados de maneira similar à de um array, visto na disciplina Programação Orientada a Objetos I, mas com maior flexibilidade.

Leia mais

Programação Orientada a Objetos. Vagner Luz do Carmo - Vluzrmos

Programação Orientada a Objetos. Vagner Luz do Carmo - Vluzrmos Programação Orientada a Objetos Vagner Luz do Carmo - Vluzrmos Questão 1 Dada a seguinte classe na linguagem JAVA: public class Carro { public String retornacor(){ ; return Azul ; private String retornachassi(){

Leia mais