PADRÕES DE PROJETO EM OOERLANG UNIVERSIDADE DO ESTADO DO AMAZONAS - UEA. Manaus ESCOLA SUPERIOR DE TECNOLOGIA ENGENHARIA DE COMPUTAÇÃO

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

Download "PADRÕES DE PROJETO EM OOERLANG UNIVERSIDADE DO ESTADO DO AMAZONAS - UEA. Manaus ESCOLA SUPERIOR DE TECNOLOGIA ENGENHARIA DE COMPUTAÇÃO"

Transcrição

1 UNIVERSIDADE DO ESTADO DO AMAZONAS - UEA ESCOLA SUPERIOR DE TECNOLOGIA ENGENHARIA DE COMPUTAÇÃO WILLIAM BREMGARTNER BELLEZA PADRÕES DE PROJETO EM OOERLANG Manaus 2013

2 WILLIAM BREMGARTNER BELLEZA PADRÕES DE PROJETO EM OOERLANG Trabalho de Conclusão de Curso apresentado à banca avaliadora do Curso de Engenharia de Computação, da Escola Superior de Tecnologia, da Universidade do Estado do Amazonas, como pré-requisito para obtenção do título de Engenheiro de Computação. Orientador: Prof. Dr. Jucimar Maia da Silva Júnior Manaus 2013

3 ii Universidade do Estado do Amazonas - UEA Escola Superior de Tecnologia - EST Reitor: Cleinaldo de Almeida Costa Vice-Reitor: Raimundo de Jesus Teixeira Barradas Diretor da Escola Superior de Tecnologia: Cleto Cavalcante de Souza Leal Coordenador do Curso de Engenharia de Computação: Raimundo Corrêa de Oliveira Coordenador da Disciplina Projeto Final: Tiago Eugenio de Melo Banca Avaliadora composta por: Data da Defesa: 18/11/2013. Prof. Dr. Jucimar Maia da Silva Júnior (Orientador) Prof. Dr. Raimundo Corrêa de Oliveira Prof. Dr. Ricardo da Silva Barboza CIP - Catalogação na Publicação B438p BELLEZA, William B. Padrões de Projeto em ooerlang / William Bremgartner Belleza; [orientado por] Prof. Dr. Jucimar Maia da Silva Júnior - Manaus: UEA, p.: il.; 30cm Inclui Bibliografia Trabalho de Conclusão de Curso (Graduação em Engenharia de Computação). Universidade do Estado do Amazonas, CDU:

4 iii WILLIAM BREMGARTNER BELLEZA PADRÕES DE PROJETO EM OOERLANG Trabalho de Conclusão de Curso apresentado à banca avaliadora do Curso de Engenharia de Computação, da Escola Superior de Tecnologia, da Universidade do Estado do Amazonas, como pré-requisito para obtenção do título de Engenheiro de Computação. BANCA EXAMINADORA Aprovado em: 18/11/2013 Prof. Jucimar Maia da Silva Júnior, Doutor UNIVERSIDADE DO ESTADO DO AMAZONAS Prof. Raimundo Corrêa de Oliveira, Doutor UNIVERSIDADE DO ESTADO DO AMAZONAS Prof. Ricardo da Silva Barboza, Doutor UNIVERSIDADE DO ESTADO DO AMAZONAS

5 iv Agradecimentos Agradeço primeiramente a Deus por ter me dado forças ao longo de toda essa caminhada, não apenas na realização deste trabalho como também por todo o período em que estive na faculdade. Agradeço aos meus pais Wilmar e Maria, por todo o apoio assim como ao meu irmão Brian que muito me incentivou e auxiliou nessa jornada. À minha companheira Miriane pela ajuda e compreensão sempre presentes e que foram o diferencial para mim. Aos amigos com quem tive o privilégio de estudar e, principalmente, ao meu orientador, o prof. Dr. Jucimar Jr., pelos seus ensinamentos e orientações que muito me ajudaram e ajudarão daqui em diante. Muito obrigado a todos!

6 v Resumo Padrões de Projetos são métodos de modelagem para vários tipos de problemas com foco na programação orientada a objetos. Estes padrões foram descobertos e documentados para serem corretamente utilizados quando for preciso, sendo aplicáveis a qualquer linguagem orientada a objetos, baseados nos princípios de design para programação orientada a objetos. ooerlang é uma extensão da linguagem Erlang, com suporte à modelagem orientada a objetos. Com a utilização da extensão ooerlang, pode-se modelar problemas utilizando-se dos vários tipos de Padrões de Projetos existentes. Palavras-Chave: Padrões, Projetos, Princípios, Objeto, Erlang, ooerlang

7 vi Abstract Design Patterns are modeling methods to several kinds of problems focused in object oriented programming. These patterns were discovered and documented to be correctly used when they are needed, being applicable to any oriented objects programming language, based on the design principles to object-oriented programming. ooerlang is an extension of Erlang language, with support to object oriented modeling. With use of ooerlang extension, it is possible to model problems using various types of Design Patterns. Keywords: Design, Patterns, Principles, Object, Erlang, ooerlang

8 vii Sumário Lista de Figuras Lista de Códigos xi xiii 1 Introdução Conceitos do Paradigma Orientado a Objetos Vantagens e problemas da programação orientada a objetos Princípios de Design Padrões de Projeto Padrões de Criação Padrões Estruturais Padrões Comportamentais A Linguagem Funcional Erlang A linguagem de programação ooerlang Trabalhos Relacionados Objetivo Geral Objetivos Específicos Justificativa Metodologia Organização da Monografia Sintaxe do ooerlang Conceitos Iniciais Estrutura de um fonte em ooerlang Classes com métodos principais e interfaces em ooerlang Utilização de herança e implementação de interface em ooerlang Observações finais da sintaxe do ooerlang

9 viii 3 Padrões de Projeto de Criação Conceitos Iniciais Padrão Abstract Factory Exemplo utilizado para este padrão Comparação das implementações em Java e ooerlang Padrão Builder Exemplo utilizado para este padrão Comparação das implementações em Java e ooerlang Padrão Factory Method Exemplo utilizado para este padrão Comparação das implementações em Java e ooerlang Padrão Prototype Exemplo utilizado para este padrão Comparação das implementações em Java e ooerlang Padrão Singleton Exemplo utilizado para este padrão Comparação das implementações em Java e ooerlang Conclusões dos Padrões de Projeto de Criação em ooerlang Padrões de Projeto Estruturais Conceitos Iniciais Padrão Adapter Exemplo utilizado para este padrão Comparação das implementações em Java e ooerlang Padrão Bridge Exemplo utilizado para este padrão Comparação das implementações em Java e ooerlang Padrão Composite Exemplo utilizado para este padrão Comparação das implementações em Java e ooerlang Padrão Decorator Exemplo utilizado para este padrão Comparação das implementações em Java e ooerlang Padrão Facade Exemplo utilizado para este padrão Comparação das implementações em Java e ooerlang Padrão Flyweight

10 ix Exemplo utilizado para este padrão Comparação das implementações em Java e ooerlang Padrão Proxy Exemplo utilizado para este padrão Comparação das implementações em Java e ooerlang Conclusões dos Padrões de Projeto Estruturais em ooerlang Padrões de Projeto Comportamentais Conceitos Iniciais Padrão Chain of Responsibility Exemplo utilizado para este padrão Comparação das implementações em Java e ooerlang Padrão Command Exemplo utilizado para este padrão Comparação das implementações em Java e ooerlang Padrão Interpreter Exemplo utilizado para este padrão Comparação das implementações em Java e ooerlang Padrão Iterator Exemplo utilizado para este padrão Comparação das implementações em Java e ooerlang Padrão Mediator Exemplo utilizado para este padrão Comparação das implementações em Java e ooerlang Padrão Memento Exemplo utilizado para este padrão Comparação das implementações em Java e ooerlang Padrão Observer Exemplo utilizado para este padrão Comparação das implementações em Java e ooerlang Padrão State Exemplo utilizado para este padrão Comparação das implementações em Java e ooerlang Padrão Strategy Exemplo utilizado para este padrão Comparação das implementações em Java e ooerlang Padrão Template Method

11 x Exemplo utilizado para este padrão Comparação das implementações em Java e ooerlang Padrão Visitor Exemplo utilizado para este padrão Comparação das implementações em Java e ooerlang Conclusões dos Padrões de Projeto Comportamentais em ooerlang Conclusão Trabalhos Futuros Referências Bibliográficas 220

12 xi Lista de Figuras 1.1 Exemplo de uma classe chamada Pessoa Exemplo de uma associação entre as classes Produto e Fornecedor Exemplo de uma agregação da classe Produto na classe Cesta Exemplo de uma composição da classe Fornecedor na classe Contato Exemplo de herança entre superclasses e subclasses na orientação à objetos Exemplo de uma interface IAluno e sua implementação na classe Aluno Diagrama de classes do exemplo para o padrão Abstract Factory Execução do exemplo para o padrão Abstract Factory em Java Execução do exemplo para o padrão Abstract Factory em ooerlang Diagrama de classes do exemplo para o padrão Builder Execução do exemplo para o padrão Builder em Java Execução do exemplo para o padrão Builder em ooerlang Diagrama de classes do exemplo para o padrão Factory Method Execução do exemplo para o padrão Factory Method em Java Execução do exemplo para o padrão Factory Method em ooerlang Diagrama de classes do exemplo para o padrão Prototype Execução do exemplo para o padrão Prototype em Java Execução do exemplo para o padrão Prototype em ooerlang Diagrama de classes do exemplo para o padrão Singleton Execução do exemplo para o padrão Singleton em Java Execução do exemplo para o padrão Singleton em ooerlang Diagrama de classes do exemplo para o padrão Adapter Execução do exemplo para o padrão Adapter em Java Execução do exemplo para o padrão Adapter em ooerlang Diagrama de classes do exemplo para o padrão Bridge Execução do exemplo para o padrão Bridge em Java

13 xii 4.6 Execução do exemplo para o padrão Bridge em ooerlang Diagrama de classes do exemplo para o padrão Composite Execução do exemplo para o padrão Composite em Java Execução do exemplo para o padrão Composite em ooerlang Diagrama de classes do exemplo para o padrão Decorator Execução do exemplo para o padrão Decorator em Java Execução do exemplo para o padrão Decorator em ooerlang Diagrama de classes do exemplo para o padrão Facade Execução do exemplo para o padrão Facade em Java Execução do exemplo para o padrão Facade em ooerlang Diagrama de classes do exemplo para o padrão Flyweight Execução do exemplo para o padrão Flyweight em Java Execução do exemplo para o padrão Flyweight em ooerlang Diagrama de classes do exemplo para o padrão Proxy Execução do exemplo para o padrão Proxy em Java Execução do exemplo para o padrão Proxy em ooerlang Diagrama de classes do exemplo para o padrão Chain of Responsibility Execução do exemplo para o padrão Chain of Responsibility em Java Execução do exemplo para o padrão Chain of Responsibility em ooerlang Diagrama de classes do exemplo para o padrão Command Execução do exemplo para o padrão Command em Java Execução do exemplo para o padrão Command em ooerlang Diagrama de classes do exemplo para o padrão Interpreter Execução do exemplo para o padrão Interpreter em Java Execução do exemplo para o padrão Interpreter em ooerlang Diagrama de classes do exemplo para o padrão Iterator Execução do exemplo para o padrão Iterator em Java Execução do exemplo para o padrão Iterator em ooerlang Diagrama de classes do exemplo para o padrão Mediator Execução do exemplo para o padrão Mediator em Java Execução do exemplo para o padrão Mediator em ooerlang Diagrama de classes do exemplo para o padrão Memento Execução do exemplo para o padrão Memento em Java Execução do exemplo para o padrão Memento em ooerlang Diagrama de classes do exemplo para o padrão Observer Execução do exemplo para o padrão Observer em Java

14 5.21 Execução do exemplo para o padrão Observer em ooerlang Diagrama de classes do exemplo para o padrão State Execução do exemplo para o padrão State em Java Execução do exemplo para o padrão State em ooerlang Diagrama de classes do exemplo para o padrão Strategy Execução do exemplo para o padrão Strategy em Java Execução do exemplo para o padrão Strategy em ooerlang Diagrama de classes do exemplo para o padrão TemplateMethod Execução do exemplo para o padrão Template Method em Java Execução do exemplo para o padrão Template Method em ooerlang Diagrama de classes do exemplo para o padrão Visitor Execução do exemplo para o padrão Visitor em Java Execução do exemplo para o padrão Visitor em ooerlang xiii

15 xiv Lista de Códigos Exemplo de uma classe chamada Pessoa em ooerlang Exemplo de uma classe chamada GerenciadorDePessoas em ooerlang Exemplo de uma interface chamada Figura em ooerlang Exemplo de uma classe chamada Soma em ooerlang Exemplo de uma classe chamada Circulo em ooerlang Exemplo de uma classe chamada Main em ooerlang Interface Cheese em Java Interface Cheese em ooerlang Interface PizzaIngredientFactory em Java Interface PizzaIngredientFactory em ooerlang Classe principal PizzaTestDrive em Java Classe principal PizzaTestDrive em ooerlang Classe Pizza em Java Classe Pizza em ooerlang Classe Waiter em Java Classe Waiter em ooerlang Classe principal BuilderExample em Java Classe principal BuilderExample em ooerlang Classe PizzaStore em Java Classe PizzaStore em ooerlang Classe Pizza em Java Classe Pizza em ooerlang Classe NYPizzaStore em Java

16 xv Classe NYPizzaStore em ooerlang Classe Person em Java Classe Person em ooerlang Interface Prototype em Java Interface Prototype em ooerlang Classe ChocolateBoiler em Java Classe ChocolateBoiler em ooerlang Classe principal ChocolateController em Java Classe principal ChocolateController em ooerlang Interface Duck em Java Interface Duck em ooerlang Classe TurkeyAdapter em Java Classe TurkeyAdapter em ooerlang Classe principal TurkeyTestDrive em Java Classe principal TurkeyTestDrive em ooerlang Classe Bike em Java Classe Bike em ooerlang Classe Assemble em Java Classe Assemble em ooerlang Classe principal BridgePattern em Java Classe principal BridgePattern em ooerlang Classe Composite em Java Classe Composite em ooerlang Classe Row em Java Classe Row em ooerlang Classe principal CompositeDemo em Java Classe principal CompositeDemo em ooerlang Classe Espresso em Java Classe Expresso em ooerlang Classe Soy em Java Classe Soy em ooerlang

17 xvi Classe principal StarbuzzCoffee em Java Classe principal StarbuzzCoffee em ooerlang Classe DvdPlayer em Java Classe DvdPlayer em ooerlang Classe HomeTheaterFacade em Java Classe HomeTheaterFacade em ooerlang Classe principal HomeTheaterTestDrive em Java Classe principal HomeTheaterTestDrive em ooerlang Classe TeaFlavor em Java Classe TeaFlavor em ooerlang Classe TeaFlavorFactory em Java Classe TeaFlavorFactory em ooerlang Classe TeaRestroom em Java Classe TeaRestroom em ooerlang Classe RealImage em Java Classe RealImage em ooerlang Classe ProxyImage em Java Classe ProxyImage em ooerlang Classe principal ProxyExample em Java Classe principal ProxyExample em ooerlang Interface Chain em Java Interface Chain em ooerlang Classe PositiveProcessor em Java Classe PositiveProcessor em ooerlang Classe principal TestChain em Java Classe principal TestChain em ooerlang Classe LightOnCommand em Java Classe LightOnCommand em ooerlang Classe Light em Java Classe Light em ooerlang Classe RemoteControlWithUndo em Java

18 xvii Classe RemoteControlWithUndo em ooerlang Classe principal RemoteLoader em Java Classe principal RemoteLoader em ooerlang Classe Plus em Java Classe Plus em ooerlang Classe Evaluator em Java Classe Evaluator em ooerlang Classe principal InterpreterExample em Java Classe principal InterpreterExample em ooerlang Classe DinerMenu em Java Classe DinerMenu em ooerlang Classe PancakeHouseMenu em Java Classe PancakeHouseMenu em ooerlang Classe DinerMenuIterator em Java Classe DinerMenuIterator em ooerlang Classe Waitress em Java Classe Waitress em ooerlang Classe principal MenuTestDrive em Java Classe principal MenuTestDrive em ooerlang Classe Flight em Java Classe Flight em ooerlang Classe ATCMediator em Java Classe ATCMediator em ooerlang Classe principal MediatorExample em Java Classe principal MediatorExample em ooerlang Classe Memento em Java Classe Memento em ooerlang Classe Originator em Java Classe Originator em ooerlang Classe principal MementoExample em Java Classe principal MementoExample em ooerlang

19 xviii Classe CurrentConditionsDisplay em Java Classe CurrentConditionsDisplay em ooerlang Classe WeatherData em Java Classe WeatherData em ooerlang Classe principal WeatherStation em Java Classe principal WeatherStation em ooerlang Classe NoQuarterState em Java Classe NoQuarterState em ooerlang Classe GumballMachine em Java Classe GumballMachine em ooerlang Classe principal GumballMachineTestDrive em Java Classe principal GumballMachineTestDrive em ooerlang Classe Duck em Java Classe Duck em ooerlang Classe MallardDuck em Java Classe MallardDuck em ooerlang Classe FlyWithWings em Java Classe FlyWithWings em ooerlang Classe principal MiniDuckSimulator em Java Classe principal MiniDuckSimulator em ooerlang Classe CaffeineBeverage em Java Classe CaffeineBeverage em ooerlang Classe Coffee em Java Classe Coffee em ooerlang Classe CoffeeWithHook em Java Classe CoffeeWithHook em ooerlang Classe principal BeverageTestDrive em Java Classe principal BeverageTestDrive em ooerlang Classe Car em Java Classe Car em ooerlang Classe Wheel em Java

20 xix Classe Wheel em ooerlang Classe CarElementDoVisitor em Java Classe CarElementDoVisitor em ooerlang Classe principal VisitorExample em Java Classe principal VisitorExample em ooerlang

21 Capítulo 1 Introdução O paradigma de programação orientado a objetos busca uma forma de programação que tenta imitar o mundo real. Neste paradigma são trabalhados vários objetos, assim como na realidade. E cada objeto possui atributos e métodos, podendo conversar, trocar mensagens e interagir entre si. Cada objeto pode ser reutilizado para outras finalidades. A orientação a objetos é um modo natural de pensar sobre o mundo e de escrever programas de computador [Deitel and Deitel, 2010]. Para melhor compreensão, são explicados na seção sobre conceitos do paradigma orientado a objetos as principais definições que caracterizam e são utilizadas de forma geral na orientação à objetos. 1.1 Conceitos do Paradigma Orientado a Objetos Assim como os paradigmas de programação funcional e estruturado, o paradigma orientado a objetos possui algumas características e conceitos que necessitam ser compreendidos para melhor entendimento do mesmo. Os conceitos explicados nesta seção são: Objeto, Classe, Associação, Agregação, Composição, Herança, Polimorfismo (e suas derivações), Encapsulamento e Interfaces. Objeto: É uma entidade que possui atributos, comportamentos, e se relaciona com outros objetos por meio de mensagens. Um objeto pode ser algo concreto ou abstrato.

22 Conceitos do Paradigma Orientado a Objetos 2 Objetos propiciam maior compreensão do mundo real e possuem responsabilidade sobre si [Dall Oglio, 2009]. Dessa forma podemos dizer que objetos são um dos principais focos deste paradigma. Classe: É uma estrutura estática utilizada para descrever (moldar) objetos, sendo um modelo para criação de objetos [Dall Oglio, 2009]. Um exemplo de classe pode ser visto na figura 1.1. Existem dois tipos de classes, entidades do negócio da aplicação, sendo as classes diretamente relacionadas com a aplicação e entidades de interface, que estão relacionadas com a parte gráfica de uma aplicação. Um objeto é uma instancia de uma classe [Dall Oglio, 2009]. Figura 1.1: Exemplo de uma classe chamada Pessoa. Associação: É a relação mais comum entre dois objetos, na qual um objeto possui uma referência à outro objeto, podendo visualizar seus atributos ou mesmo acionar uma de suas funcionalidades [Dall Oglio, 2009]. Um forma simples para se obter uma associação, seria a de utilizar um objeto como atributo de outro objeto, desta forma um objeto está relacionado ao outro. Um exemplo de associação pode ser observado na figura 1.2. Agregação: É o tipo de relação entre objetos conhecida como todo/parte, na qual um objeto referencia objeto(s) externo(s) dentro de si [Dall Oglio, 2009]. Uma forma simples de implementar a agregação é utilizando uma lista como atributo de um objeto, possuindo diversas instâncias deste objeto nesta lista. O objeto-pai poderá

23 Conceitos do Paradigma Orientado a Objetos 3 Figura 1.2: Exemplo de uma associação entre as classes Produto e Fornecedor. agregar uma ou muitas instâncias de outro objeto e poderá utilizar funcionalidades do objeto agregado [Dall Oglio, 2009]. Dessa forma, um objeto contém instâncias de outros objetos. Pode-se observar uma forma de utilização da agregação ilustrada na figura 1.3. A principal diferença em relação à associação é que na agregação existe mais em um objeto sendo utilizado como atributo de outra classe (arranjo de objetos, por exemplo). Figura 1.3: Exemplo de uma agregação da classe Produto na classe Cesta. Composição: Assim como a agregação, a composição também é uma relação todo/parte. A diferença está no fato de que o todo e as partes são dependentes entre si, ou seja, o objeto-pai possui realmente suas partes, sendo responsável por sua criação e destruição. Quando o objeto todo é destruído, suas partes também são [Dall Oglio, 2009]. Ou seja, um objeto é composto de outros objetos. A figura 1.4 mostra um exemplo de utilização da composição. Herança: É um tipo de relacionamento que permite especializar uma classe, criar versões refinadas dela [Dall Oglio, 2009]. A herança é um bom exemplo de reutilização de códigos na orientação a objetos, quando torna possível criar novas classes que herdam atributos e métodos da classe originária. A herança é uma forma de reutilizar componentes de software aperfeiçoandos-os ou adicionando características

24 Conceitos do Paradigma Orientado a Objetos 4 Figura 1.4: Exemplo de uma composição da classe Fornecedor na classe Contato. específicas [Dall Oglio, 2009]. Uma forma de se utilizar herança está mostrada na figura 1.5, na qual as classes Funcionário e Prestador são herdeiras da classe Colaborador, assim como herdam seus atributos para as classes Empregado, Estagiário, Empresa e Autônomo. Figura 1.5: Exemplo de herança entre superclasses e subclasses na orientação à objetos. Polimorfismo: Permite que classes derivadas de uma mesma super classe tenham métodos com a mesma nomenclatura mas comportamentos diferentes, redefinidos em cada uma das classes-filha [Dall Oglio, 2009]. Seu significado refere-se a muitas formas, por permitir métodos semelhantes com execuções diferentes. O polimorfismo pode ser classificado em três formas distintas: Polimorfismo de Sobrecarga, de Sobreposição e de Inclusão.

25 Conceitos do Paradigma Orientado a Objetos 5 Polimorfismo de Sobrecarga: Este polimorfismo é caracterizado por possuir dois ou mais métodos com o mesmo nome, porém diferentes quantidades e tipos de parâmetros. Para cada método haverá um comportamento diferente e, apesar do nome ser semelhante, o resultado será distinto, dependendo dos parâmetros de entrada do método em questão. Polimorfismo de Sobreposição: Nesta classe de polimorfismo, um método de uma superclasse é redefinido por uma subclasse que o herda. Neste caso, apesar de o método possuir mesmo nome e mesmos parâmetros, quando utilizado pela subclasse, o comportamento será diferente, devido ao fato do método ter sido sobreposto ao método originalmente herdado da superclasse. Polimorfismo de Inclusão: Nesta classe de polimorfismo as classes que herdam de uma superclasse são utilizadas para substituir a superclasse na construção de um objeto (passando a classe por parâmetro), por exemplo. Devido a isto, cada subclasse que substituir a superclasse irá fazer com que o objeto possua um comportamento diferente, relacionado com a classe que substituiu a superclasse. Encapsulamento: É uma característica de todas as linguagens de programação que implementam tipos abstratos de dados. Na orientação a objetos, visa proteger aspectos dos objetos que não devem ser modificados ou vistos dos aspectos que são visíveis aos usuários. Trata-se de uma proteção a um conteúdo do objeto, separando os aspectos externos de um objeto de seus detalhes internos. É uma forma de proteger certos atributos, evitando que os mesmos contenham valores inconsistentes ou sejam manipulados indevidamente [Dall Oglio, 2009]. Interface: Sabendo-se que os objetos relacionam-se entre si e que é importante que um objeto saiba quais métodos os objetos com quem ele se relaciona possuem, interfaces são tipos de classes que possuem apenas uma assinatura dos métodos que uma classe deverá implementar. Uma classe que implementar uma interface deverá obrigatoriamente possuir os métodos pré-definidos na interface [Dall Oglio, 2009]. A figura 1.6 mostra a utilização de uma interface chamada IAluno, onde seus métodos são implementados em uma classe chamada Aluno.

26 Vantagens e problemas da programação orientada a objetos 6 Figura 1.6: Exemplo de uma interface IAluno e sua implementação na classe Aluno. 1.2 Vantagens e problemas da programação orientada a objetos Uma das principais vantagens no uso do paradigma de orientação a objetos para modelagem de projetos é a possibilidade da reutilização de códigos. A facilidade de codificação é outro fator positivo neste paradigma. Esta facilidade é consequência de outro fator vantajoso na orientação a objetos, o alto nível de abstração desta linguagem. Para projetos bem modelados, o ciclo de vida de um sistema pode ser bastante longo, pois a dificuldade de manutenção e reutilização do código torna-se pequena. A programação orientada a objetos também possui algumas desvantagens, podendo ser citado entre elas: complexidade no aprendizado para desenvolvedores de linguagens de programação estruturada, maior esforço na modelagem de um sistema orientado a objetos em relação ao estruturado (apesar da codificação possuir um nível de abstração maior em comparação com linguagens de programação estruturadas), funcionalidades limitadas por interfaces ainda não completadas, dependência de funcionalidades já implementadas em superclasses, no caso específico da utilização de herança, por exemplo. 1.3 Princípios de Design Ao estruturar um projeto orientado a objetos, geralmente observam-se padrões de comportamento de objetos que podem ser semelhantes ou de alguma forma parecidos. Um

27 Princípios de Design 7 dos objetivos da programação orientada a objetos é o de simplificar as implementações o máximo possível. Neste caso de semelhança entre objetos, existe uma forma de implementação chamada herança, em que uma classe superior, chamada superclasse, tem seus métodos herdados para outras classes semelhantes a ela. Desta forma, pode existir uma classe mais geral, como por exemplo insetos, e várias classes mais específicas, por exemplo, mosca, formiga, gafanhoto entre outras. E todos os métodos que fossem comuns a todos os tipos de insetos iriam estar na classe inseto e todas as classes que herdassem esta classe também herdariam os métodos da superclasse. Esta forma de implementação facilita por simplificar o desenvolvimento de uma solução para certo problema ou situação. Entretanto, a herança possui uma característica importante a ser observada: acoplamento forte entre classes. Isto significa dizer que sempre que uma superclasse for modificada, esta mudança irá influenciar todas as subclasses que a herdam. E desta forma a reutilização de código torna-se algo mais difícil de ser realizada, assim como a manutenção. E é neste aspecto (e em outros) que foram documentados os princípios de design na programação orientada a objetos, assim como os padrões de projetos, que são importantes por utilizarem diferentes soluções que podem ser aplicadas a situações conhecidas, tendo como objetivo um código o menos acoplado possível (acoplamento é quando uma classe é dependente de uma ou várias classes), mais fácil de ser reutilizado, mantido e modificado. Os princípios de design para programação orientada a objetos foram definidos por diferentes autores, sendo documentados e publicados por Robert Cecil Martin em meados de No total são 11 (onze) princípios básicos para que se obtenha um design de projeto orientado a objetos desacoplado, de fácil manutenção, extensão e reutilização. Vejamos estes princípios com mais detalhes: The Single Responsibility Principle (Princípio da responsabilidade única): Uma classe deve possuir apenas uma razão para mudar [Martin and Martin, 2006]. Isto significa dizer que não deve haver mais de uma razão para uma classe mudar. Cada classe deve possuir apenas uma responsabilidade e, se uma classe possuir mais de uma responsabilidade, deve-se decompor esta classe em outras subclasses. The Open-Closed Principle (Princípio aberto-fechado): Entidades de software (classes, módulos, funções etc) devem ser abertos para extensão, porém fechados para

28 Princípios de Design 8 modificação [Martin and Martin, 2006]. Este princípio orienta que cada entidade de software não pode ser modificada, apenas estendida em suas funcionalidades, evitando assim erros de projetos mal modelados. The Liskov Substitution Principle (Princípio da substituição de Liskov): Subtipos devem ser substituíveis por seus tipos bases [Martin and Martin, 2006]. Este princípio defende que uma instância de uma subclasse deve poder substituir uma instância de sua superclasse, sem que isso cause problema na execução do programa. The Dependency Inversion Principle (Princípio da inversão de dependência): Abstrações não devem depender de detalhes. Detalhes devem depender de abstrações [Martin and Martin, 2006]. A idéia deste princípio é a de que classes devem depender de classes mais abstratas ou de interfaces, por exemplo. Isto evita dependências desnecessárias entre classes, permitindo um código mais desacoplado. The Interface Segregation Principle (Princípio da segregação de interface): Clientes não devem ser forçados a depender de métodos que eles não utilizam. Interfaces pertencem a clientes e não a hierarquias [Martin and Martin, 2006]. De acordo com este princípio, devem ser evitadas interfaces que possuem muitos métodos, não usados por clientes, assim como se deve evitar forçar o cliente a utilizar um método de uma interface que o mesmo não queira. The Release-Reuse Equivalency Principle (Princípio da Equivalência de Liberação e Reuso): A granularidade do reuso é a granularidade da liberação [Martin and Martin, 2006]. O fundamento deste princípio visa à integração de mudanças na reutilização de códigos. Não é certo reutilizar códigos apenas copiando de uma classe para outra, pois isto poderia gerar futuros problemas de ambiguidade. Deve existir um controle quando ocorrem mudanças em um pacote, para que não afete o código já existente. The Common Closure Principle (Princípio do acoplamento comum): As classes em um pacote devem ser acopladas juntas contra qualquer tipo de mudanças. Uma mudança que afeta um pacote fechado afeta todas as classes daquele pacote e nenhum outro pacote [Martin and Martin, 2006]. Para este princípio, todas as classes de um

29 Padrões de Projeto 9 pacote e apenas deste pacote devem ser afetados quando ocorre uma modificação neste pacote. Isto permite a integridade de classes dentro de um pacote. The Common Reuse Principle (Princípio da reutilização comum): As classes em um pacote são reutilizadas juntas. Se você reutilizar uma das classes em um pacote, você irá reutilizar todas elas [Martin and Martin, 2006]. Isto existe pelo fato de cada pacote possuir um conjunto de classes liberadas, ou seja, uma mudança em uma classe significa uma liberação nova de todo o pacote. The Acyclic Dependencies Principle (Princípio das dependências acíclicas): Não permita ciclos no grafo de dependência de pacotes [Martin and Martin, 2006]. Este princípio defende que a estrutura de dependências entre pacotes deve ser um grafo acíclico, sendo proibida a possibilidade de, ao seguir qualquer linha de dependência, se retorne a um pacote antes visitado. The Stable Dependencies Principle (Princípio das dependências estáveis): Dependência na direção da estabilidade [Martin and Martin, 2006]. Este princípio defende que a dependência de pacotes em um design de projetos deve sempre seguir para pacotes mais estáveis, ou seja, pacotes devem sempre depender de outros pacotes mais estáveis que os próprios. The Stable Abstractions Principle (Princípio das abstrações estáveis): Um pacote deve ser tão abstrato quanto é estável [Martin and Martin, 2006]. Isto significa dizer que pacotes que são altamente estáveis devem ser altamente abstratos. Pacotes instáveis devem ser concretos. A abstração de um pacote deve ser diretamente proporcional à sua estabilidade. 1.4 Padrões de Projeto Padrões de Projetos são arquiteturas comprovadas para construir software orientado a objetos flexível e fácil de manter [Deitel and Deitel, 2010]. Foram definidos vinte e três (23) diferentes tipos de padrões de projetos. Estes padrões foram desenvolvidos com base em diferentes problemas, quando uma solução trivial não é aplicável a uma determinada

30 Padrões de Projeto 10 situação, sendo subdivididos em diferentes tipos de padrões de projetos, de acordo com sua aplicação, e devidamente documentados para serem utilizados corretamente. Os padrões de projetos já são a solução dos principais tipos de problemas em orientação à objetos [Freeman et al., 2004]. Eles foram definidos e documentados por quatro (4) desenvolvedores de projetos com orientação à objetos, Erich Gamma, Richard Helm, Ralph Johnson e John Vlissides. Estes autores são conhecidos como a Gang of Four (gangue dos quatro), ou simplesmente GoF. A correta utilização destes padrões é bastante recomendável, tendo em vista que ajudam na coesão, consistência, manutenção, reutilização e melhoria de código-fonte. Também auxiliam todo e qualquer desenvolvedor a melhorar sua modelagem de um problema específico. Podem ser utilizados isoladamente ou em conjunto, não tendo entre si uma utilização isolada ou mutuamente exclusiva. Os padrões de projetos foram estudados e definidos de acordo com a sua aplicabilidade e o contexto em que podem ser utilizados. Portanto, cada padrão possui uma implementação característica do mesmo. Estes padrões variam na sua granularidade e nível de abstração, sendo necessário organizá-los [Gamma et al., 1994]. Existem algumas formas de classificar todos os padrões de projetos, uma delas é dividindo em três tipos de classificação: padrões de criação, padrões estruturais e padrões comportamentais Padrões de Criação São padrões que ajudam a fazer um sistema independente de como seus objetos são criados, construídos e representados [Gamma et al., 1994]. Cinco (5) padrões possuem esta classificação: Abstract Factory, Builder, Factory Method, Prototype, Singleton Padrões Estruturais Padrões estruturais estão preocupados em como classes e objetos são compostos para formar estruturas maiores [Gamma et al., 1994]. Sete (7) padrões completam esta classificação: Adapter, Bridge, Composite, Decorator, Facade, Flyweight, Proxy.

31 A Linguagem Funcional Erlang Padrões Comportamentais Padrões comportamentais estão preocupados com algoritmos e a atribuição de responsabilidades entre objetos, descrevendo não apenas padrões de objetos ou classes, mas também padrões de comunicação entre eles [Gamma et al., 1994]. Ao todo onze (11) padrões estão inclusos nesta classificação: Chain of Responsibility, Command, Interpreter, Iterator, Mediator, Memento, Observer, State, Strategy, Template Method, Visitor. 1.5 A Linguagem Funcional Erlang Erlang é uma linguagem de programação inicialmente criada para a empresa de telecomunicações Ericsson. Seu nome deriva de Ericsson Language. Seu paradigma é funcional, e o principal foco desta linguagem é a capacidade de trabalhar com diversas requisições em paralelo assim como conseguir se recuperar de alguma falha sem deixar todo o sistema inativo. Erlang foi projetado para programação concorrente, em tempo real, com sistemas tolerantes a falhas e distribuídos [Armstrong, 1996]. A linguagem de programação Erlang é bastante utilizada por diversos desenvolvedores, por vários motivos: Programas escritos em Erlang executam mais rápido em computadores com múltiplos núcleos de processamento, aplicações em Erlang podem ser tolerantes a falhas e podem ser modificadas em tempo de execução. A linguagem Erlang já foi testada em produtos de larga escala industrial [Armstrong, 2007]. 1.6 A linguagem de programação ooerlang O paradigma de programação funcional é diferente do paradigma orientado a objetos. O primeiro é baseado em funções e seus retornos. O segundo é baseado nos objetos das classes e nas relações entre estes objetos. Fazer com que uma linguagem funcional tenha suporte para orientação a objetos não é tarefa simples, tendo-se em vista que são abordagens bastante distintas, formas diferentes de se modelar um problema específico. Iremos agora descrever o ooerlang. Trata-se de um acréscimo na linguagem de programação Erlang, incluindo a possibilidade de programar com orientação a objetos utilizando-

32 Trabalhos Relacionados 12 se das principais características da linguagem funcional Erlang, mas com outra abordagem de modelagem. O ooerlang supre o Erlang no que diz respeito à possibilidade de programar com orientação à objetos. Portanto, ooerlang é uma extensão orientada a objetos para a linguagem de programação Erlang [Jr. and Lins, 2012]. A extensão ooerlang foi possível ser desenvolvida com um acréscimo no compilador original da linguagem Erlang, fazendo com que fosse possível trabalhar com orientação a objetos. Isto significa que é possível criar classes, instanciar objetos, programar para interfaces, etc. Tornar o Erlang orientado a objetos pode ser uma estratégia para alcançar um público mais extenso, provavelmente com maior visibilidade e aceitação [Jr. et al., 2012]. Para desenvolvedores da linguagem Erlang que necessitem trabalhar com uma linguagem orientada a objetos, ooerlang é uma alternativa fortemente recomendada, por ter uma sintaxe de fácil assimilação e características básicas de conceitos de orientação a objetos fáceis de serem implementados e testados [da Silva Júnior, 2013]. Sua sintaxe simples, próxima de outras linguagens de programação largamente utilizadas como Java, tornam fácil sua adoção [Jr. and Lins, 2012]. 1.7 Trabalhos Relacionados Protótipo de Software para geração de sistemas distribuídos utilizando Design Patterns [OSS, 2001]: Este trabalho é de pesquisa e implementação de um protótipo para geração de sistemas distribuídos utilizando alguns padrões de projetos; Um estudo de Design Patterns no desenvolvimento em PHP 5 [Grzesiuk, 2006]: Este trabalho é de estudo e pesquisa acerca da utilização de Design Patterns no desenvolvimento do PHP 5; Padrões de Projeto: Uma compilação dos mais utilizados em projetos de software [de Souza Pereira, 2008]: Este trabalho está focado no estudo dos padrões de projetos mais utilizados, destacando as características dos principais.

33 Objetivo Geral Objetivo Geral Implementar formas de utilização de todos os Padrões de Projetos utilizando-se da extensão da linguagem Erlang chamada ooerlang, testando as implementações realizadas e verificando os resultados obtidos, analisando a execução dos respectivos padrões. 1.9 Objetivos Específicos Implementar um exemplo prático de utilização dos padrões de projeto para cada um dos cinco (5) Padrões de Criação existentes, em Java e ooerlang; Implementar um exemplo prático de utilização dos padrões de projeto para cada um dos sete (7) Padrões Estruturais existentes, em Java e ooerlang; Implementar um exemplo prático de utilização dos padrões de projeto para cada um dos onze (11) Padrões Comportamentais existentes, em Java e ooerlang; Compilar os fontes em Java e ooerlang resultantes das implementações; Testar os fontes compilados dos padrões de projetos, verificando se os resultados obtidos em Java e ooerlang são semelhantes Justificativa Para os desenvolvedores que possuem conhecimento na linguagem de programação Erlang, e também necessitem de uma solução para um problema do tipo orientado a objetos, a utilização do ooerlang é uma boa alternativa. Implementar padrões de projetos utilizandose desta extensão do Erlang pode ser uma opção inteligente na construção e manutenção de problemas cuja melhor solução nem sempre é a mais fácil. A extensão ooerlang possui uma sintaxe bastante próxima gramaticalmente de linguagens de programação orientadas a objetos como o Java, o que facilita seu uso e suas aplicações em diversos tipos de problemas ou situações. Desenvolvedores de projetos em linguagem de programação com paradigma orientado a objetos assim como programadores

34 Metodologia 14 da linguagem Erlang podem facilmente se adaptar ao ooerlang, utilizando-o como ferramenta de desenvolvimento de projetos. Mostrar que esta extensão possibilita a implementação de todos os padrões de projetos definidos e documentados, confirma o ooerlang como sendo uma ferramenta bastante útil em diversos tipos de projetos com o foco na orientação à objetos. Os trabalhos relacionados a este que foram citados anteriormente também tratam do tema Design Patterns como foco principal, mas nenhum deles trabalha com todos os vinte e três (23) padrões de projetos existentes. Além disso, nem todos os trabalhos são de desenvolvimento, limitando-se apenas à pesquisa científica e documentação Metodologia Inicialmente é utilizada a sintaxe da extensão ooerlang para implementar exemplos de utilização de todos os 23 diferentes padrões de projetos documentados, dando ênfase para as características específicas de cada padrão. Para cada exemplo em ooerlang, existe um exemplo semelhante em Java, para que seja possível comparar o comportamento de ambas as implementações. Cada exemplo procura tratar especificamente do escopo no qual o padrão de projeto visa melhorar. Os exemplos implementados também são documentados e são salvos no repositório Github (sistema de controle de versão e gerenciamento de código-fonte, desenvolvido originalmente para Linux) para que se tenha melhor entendimento da forma como o padrão de projeto é aplicado para resolver determinado problema, assim como para que fique mais claro perceber as pequenas diferenças entre cada tipo de padrão de projeto. Em seguida os padrões implementados são compilados e testados, havendo assim a comprovação da correta implementação e aplicação destes padrões em diferentes problemas. Os resultados obtidos são analisados, com o intuito de verificar se são realmente os resultados que estavam sendo esperados. Todo o processo de desenvolvimento e geração das implementações dos fontes do oo- Erlang é interativo e incremental. Isto significa dizer que cada implementação é testada e validada antes que se passe à próxima. Para armazenar os códigos implementados de forma segura, é utilizado novamente o repositório Github, salvando-os e mantendo-os atualizados.

35 Organização da Monograa 15 Após o processo de implementação e testes ser concluído, é feita a documentação das implementações, dos testes e dos resultados obtidos. Cada padrão implementado e testado irá ser documentado de acordo com suas características próprias e com sua abordagem no que diz respeito ao problema que o padrão específico procura resolver Organização da Monografia Este trabalho está estruturado nos seguintes capítulos: Capítulo 2: Sintaxe do ooerlang Neste capítulo são apresentadas as principais características da sintaxe utilizada na codificação de fontes em ooerlang, definindo a estrutura principal de classes e interfaces nesta extensão do Erlang voltada à orientação à objetos. Capítulo 3: Padrões de Projeto de Criação Este capítulo trata das implementações em ooerlang de exemplos da utilização de todos os padrões de projeto de criação, explicando as características próprias de cada utilização dos padrões para situações específicas nas quais os mesmos podem ser utilizados. Capítulo 4: Padrões de Projeto Estruturais Este capítulo mostra os exemplos de utilização dos padrões de projetos estruturais utilizando-se do ooerlang, e de suas características próprias de sintaxe e regras de implementação. Cada exemplo é detalhado em suas peculiaridades, sendo explicado o motivo para utilização de cada padrão. Capítulo 5: Padrões de Projeto Comportamentais Semelhante aos capítulos anteriores, este mostra como o ooerlang pode ser utilizado para aplicar os padrões de projetos que se encaixam na classificação dos comportamentais, explicando as características próprias de cada padrão e as decisões de implementação dos mesmos. Capítulo 6: Conclusão e Trabalhos Futuros Neste capítulo é apresentada a conclusão obtida após o desenvolvimento de todo o projeto, analisando os resultados provenientes das implementações dos exemplos dos padrões, assim como são sugeridos trabalhos futuros relacionados a este tema.

36 Capítulo 2 Sintaxe do ooerlang Neste capítulo é tratado a respeito da sintaxe própria da extensão do Erlang para suportar o paradigma orientado à objetos, ooerlang. A extensão ooerlang tem como base fundamental o próprio Erlang. O compilador do ooerlang é o mesmo compilador do Erlang, porém com as modificações necessárias para o suporte da orientação à objetos. A sintaxe de uma forma geral é silimar à utilizada no próprio Erlang. Algumas palavraschaves são introduzidas no compilador do ooerlang para facilitar o uso desta extensão, tornando-a bastante próxima, sintaticamente da linguagem Java, por exemplo. Mesmo assim, os elementos sintáticos do Erlang ainda estão presentes no ooerlang, uma vez que a estrutura principal do compilador original do Erlang não modificou-se consideravelmente. 2.1 Conceitos Iniciais A extensão da linguagem de programação ooerlang possui uma sintaxe própria, com elementos presentes do Erlang e também bastante semelhante à sintaxe da linguagem Java. Com a utilização desta extensão é possivel criar classes, classes abstratas e interfaces, cada uma com suas características próprias. O objetivo deste capítulo é o de explicar o ooerlang de acordo com sua sintaxe, de uma forma geral, mostrando exemplos ilustrativos de fontes em ooerlang. Na criação de uma classe ou interface em ooerlang, deve-se observar sempre que exis-

37 Estrutura de um fonte em ooerlang 17 tem três partes bem definidas ao longo do código-fonte, sendo elas: Declarações Iniciais, Atributos e Métodos. Obrigatoriamente estas partes aparecem nesta devida ordem, pois é desta forma que o compilador do ooerlang funciona. A alteração da ordem desta estrutura ocasiona erro de compilação e falha no processo de geração de executáveis. A seguir são melhor explicadas cada uma das partes. Declarações Iniciais: Encontra-se no cabeçalho do fonte, sendo utilizado para definir se estamos tratando de uma classe ou interface. Também define herança entre classes, implementação de interfaces, declaração de métodos públicos e declaração do método construtor, no caso da classe possuir um. Atributos: A segunda parte do fonte, responsável por declarar todos os atributos pertencentes à referente classe que está sendo implementada. Métodos: Esta é a parte final do fonte em ooerlang, em que são definidos os métodos utilizados pelas instâncias pertencentes à referente classe. Estes métodos podem ser públicos ou privados, e isso é definido nas declarações iniciais. 2.2 Estrutura de um fonte em ooerlang Para melhor visualizar as três partes principais dos fontes em ooerlang, observemos o fonte chamado pessoa.cerl mostrado em Inicialmente verifica-se que todos os fontes em ooerlang possuem seu nome iniciando com letra minúscula. A extensão utilizada é.cerl. Ao observar o fonte mostrado em 2.2.1, verifica-se que o mesmo possui todas as três partes utilizadas. Deve-se levar em consideração que não é obrigatório que todas as partes estejam sempre presentes. No caso de uma classe não possuir atributos, por exemplo, a parte relacionada à declaração de atributos não estará presente. No fonte 2.2.1, as três primeiras linhas representam as declarações iniciais do fonte. Na primeira linha é mostrado como declara-se uma classe, utilizando o token class. A segunda linha mostra a declaração do construtor, usando-se o token constructor, e definindo o método utilizado como construtor. Em seguida são definidos os métodos públicos.

38 Estrutura de um fonte em ooerlang class(pessoa). 2 -constructor([new/2]). 3 -export([gastar/1, receber/1]). 4 5 attributes. 6 7 Nome; 8 Nascimento; 9 DinheiroNaCarteira methods new(nome, Nasc) -> self::nome = Nome, 15 self::nascimento = Nasc, 16 self::dinheironacarteira = gastar(valor) -> 19 self::dinheironacarteira = self::dinheironacarteira - Valor receber(valor) -> 22 self::dinheironacarteira = self::dinheironacarteira + Valor. Código 2.2.1: Exemplo de uma classe chamada Pessoa em ooerlang Isto ocorre da mesma forma que no Erlang, quando são definidas as funções externas. É importante observar que, diferente do Java, no ooerlang o construtor pode possuir qualquer nome, contanto que seja declarado no início. Iniciando na linha cinco (5) e terminando na linha nove (9) do fonte estão declarados os atributos da classe, ou seja, a segunda parte do fonte em ooerlang. Inicialmente é utilizado o token attributes seguido de um ponto e em seguida cada atributo é declarado sem possuir um valor inicial. Todos os atributos iniciam com letra maiúscula, são separados por ponto-e-vírgula e, após o atributo final, é utilizado outro ponto. Importante verificar que não existe a declaração do tipo de atributo que está sendo definido em ooerlang. A terceira parte do fonte, a declaração e definição dos métodos, está presente no fonte entre as linhas onze (11) e vinte e dois (22). Semelhante à declaração de atributos, na declaração de métodos é utilizado inicialmente o token methods seguido de ponto. O método chamado new é o método construtor, definido nas declarações iniciais. Este método recebe dois parâmetros de entrada que são utilizados para inicializar os atributos da classe pessoa. Sempre que um atributo de uma classe for utilizado, a sintaxe empregada necessita

39 Classes com métodos principais e interfaces em ooerlang 19 do token self, para que o compilador saiba estar se tratando de um atributo da própria classe. Dessa forma, como mostrado nas linhas 14, 15 e 16 do fonte 2.2.1, os atributos Nome e Nascimento estão sendo inicializados com os parâmetros de entrada do construtor e o atributo DinheiroNaCarteira está recebendo valor inicial igual a zero (0). Ao inicializar os atributos, automaticamente seus tipos são definidos, de acordo com o tipo de dado que determinado atributo está recebendo ao ser inicializado. O atributo Nome, por exemplo, recebe uma cadeia de caracteres assim como o atributo DinheiroNaCarteira recebe um valor numérico. Os métodos mostrados entre as linhas 18 e 22 mostram dois métodos públicos que modificam o valor presente no atributo DinheiroNaCarteira, sendo que um método aumenta o valor neste atributo e o outro o diminui. Ao ser modificado um valor de um atributo da própria classe, após a utilização do token self são utilizados dois sinais de dois pontos ( :: ) conforme mostrado nas linhas 14, 15, 16, 19 e 22 do fonte Estes dois sinais de dois pontos seguidos são utilizados com frequência no ooerlang, tanto para referir-se a um atributo da própria classe, quanto para um objeto invocar um método, conforme é explicado nas seções seguintes. 2.3 Classes com métodos principais e interfaces em ooerlang Uma classe em ooerlang com o método principal (main) é a classe na qual são realizados os testes de execução. Seguindo a mesma regra de estruturação de um fonte, a classe principal também irá possuir as declarações iniciais, a definição de atributos e a implementação dos métodos, sejam eles públicos ou privados. Os métodos privados são os não declarados como públicos no início do fonte. O código mostrado em mostra a classe principal que utiliza a classe mostrada em Observa-se que as declarações iniciais estão nas duas primeiras linhas do fonte, declarando a classe e tornando o método principal público. Observa-se que esta classe não possui atributos, portanto, passa-se diretamente à terceira parte, declaração de métodos. A linha quatro (4) mostra o token usado ao serem declarados métodos estáticos: class methods. Este token informa ao compilador que os métodos seguintes a ele são estáticos, pertencendo

40 Classes com métodos principais e interfaces em ooerlang class(gerenciadordepessoas). 2 -export([main/0]). 3 4 class_methods. 5 6 main() -> 7 PVitor = pessoa::new("vitor Fernando Pamplona","07/11/1983"), 8 9 PVitor::receber( ), PJoao = pessoa::new("joao da Silva", "18/02/1970"), PJoao::receber(500.00), 14 PJoao::gastar(100.00). Código 2.3.1: Exemplo de uma classe chamada GerenciadorDePessoas em ooerlang à classe e não a um objeto. Na implementação dos métodos de uma classe em ooerlang, primeiro são definidos os métodos não estáticos, e em seguida os métodos estáticos, de acordo com o token utilizado no início de cada implementação. Dessa forma, ao ser necessário a uma classe possuir métodos estáticos e não-estáticos, depois da declaração de variáveis, é utilizado o token methods seguido de ponto, para definir métodos não-estáticos. Após as referidas definições, é utilizado o token class methods, seguido novamente de ponto, para definir os métodos estáticos. O fonte mostra na linha sete (7) um exemplo de instanciação utilizando o construtor definido no fonte Assim como no Erlang, no ooerlang uma nova variável é definida apenas por ser escrita, e seu tipo é definido de acordo com o valor que esta variável recebe. No caso da linha 7, é criado um objeto de nome PVitor da classe Pessoa. Este objeto recebe o resultado da invocação do construtor por meio da classe Pessoa. Assim como na manipulação de atributos, na chamada de métodos por objetos é utilizado o sinal duplo de dois pontos ( :: ). Para que um objeto chame um método de sua classe, é utilizada a forma objeto::método(parâmetro1, parâmetro2,...). Assim é criado um objeto do tipo Pessoa, com os atributos Nome e DataDeNascimento sendo passados por parâmetro para o construtor. Dessa forma o objeto PVitor passa ser uma das instâncias da classe Pessoa. A linha nove (9) do fonte mostra o objeto recém-instanciado PVitor utilizando o

41 Utilização de herança e implementação de interface em ooerlang 21 método para receber dinheiro na carteira, chamado de receber. A linha onze (11) mostra a instanciação de outro objeto, neste caso chamado de PJoao, e as linhas treze (13) e quatorze (14) representam o objeto PJoao invocando os métodos receber e gastar que estão definidos na própria classe Pessoa. A utilização de interfaces no ooerlang também utiliza as regras de estruturação das classes nesta extensão do Erlang. Existem algumas diferenças, que devem ser observadas na implementação de uma interface. Inicialmente, observa-se que interfaces, via de regra geral, não possuem atributos, e seus métodos são apenas assinaturas a serem desenvolvidas pelas classes que as implementam. interface em ooerlang. 1 -interface(figura). 2 -export([calculararea/0]). 3 4 methods. 5 6 calculararea(). O fonte mostrado em mostra um exemplo de Código 2.3.2: Exemplo de uma interface chamada Figura em ooerlang A primeira característica própria das interfaces em ooerlang está presente na primeira linha, onde é utilizado o token interface ao invés do token class que é utilizado para classes. A primeira linha, tanto para classes quanto para interfaces, representa o nome da classe ou interface, e deve coincidir com o nome do arquivo a ser implementado. A interface possui um método público definido na linha dois (2). Verifica-se também que, para definir um método abstrato em uma interface, é necessário apenas inserir um ponto após os parâmetros do referido método, conforme mostrado na linha seis (6) do fonte Utilização de herança e implementação de interface em ooerlang Assim como a linguagem Java, a extensão ooerlang pode ser utilizada para implementar o conceito de herança entre superclasses e subclasses. Desta forma, as classes que herdam

42 Utilização de herança e implementação de interface em ooerlang 22 uma classe superior passam a possuir os mesmos atributos e métodos da superclasse. Também é possível ao se utilizar herança, a redefinição de um método da classe superior. O fonte mostrado em ilustra um exemplo de uma classe que se utiliza de herança para redefinir um método da classe superior. 1 -class(soma). 2 -extends(operacaomatematica). 3 -export([calcular/2]). 4 5 methods. 6 7 calcular(x,y) -> 8 X+Y. Código 2.4.1: Exemplo de uma classe chamada Soma em ooerlang Conforme pode ser observado no código-fonte em 2.4.1, as tres primeiras linhas representam as definições iniciais da classe Soma. A segunda linha mostra como uma classe herda os atributos e métodos de uma classe com nível de abstração superior: utilizando-se do token extends. Semelhante ao Java, o ooerlang também utiliza-se deste token para representar herança. Assim, a classe Soma está herdando as características de uma classe chamada operacaomatematica. Logicamente, o método mostrado na linha sete (7) também é definido na classe operacaomatematica. A classe Soma, conforme pode ser observado no fonte em 2.4.1, não possui atributos. Desta forma, após as declarações iniciais nas três primeiras linhas, passa-se para a definição de métodos. Quando uma classe necessita estender mais de uma superclasse, os nomes das superclasses não são colocados diretamente entre parênteses, mas sim dentro de uma lista. Isto é feito de forma semelhante com a qual são declarados os métodos públicos de uma classe, conforme mostrado no fonte O fonte mostrado em representa uma interface em ooerlang que é a abstração para diferentes tipos de figuras. O fonte mostrado em mostra uma classe chamada Circulo, representando uma das classes que pode implementar esta interface, por se tratar de um tipo de figura geométrica. Esta classe deve, obrigatoriamente, implementar o método calculararea(), pois trata-se de um método abstrato da interface Figura. Para que o compilador do ooerlang entenda que a classe atual está implementando uma interface, é necessário, nas declarações iniciais, utilizar o token implements, seguido do

43 Observações nais da sintaxe do ooerlang class(circulo). 2 -implements(figura). 3 -export([calculararea/0, new/1]). 4 -constructor([new/1]). 5 6 attributes. 7 8 Raio methods new(raio) -> 13 self::raio = Raio calculararea() -> * self::raio * self::raio. Código 2.4.2: Exemplo de uma classe chamada Circulo em ooerlang nome da interface em questão, de acordo com o que está mostrado na segunda linha do fonte Esta classe possui um atributo necessário para que seja possivel o cálculo de sua área, e este atributo (Raio) é definido entre as linhas 6 e 8. Os métodos estão definidos entre as linhas 10 e 16. Além do método responsável por calcular a área do círculo, também foi definido um construtor na linha 12, sendo que este construtor foi previamente declarado na linha Observações finais da sintaxe do ooerlang Conforme demonstrado, as classes e interfaces em ooerlang, possuem três partes bem definidas: declarações iniciais, atributos e métodos. Nas declarações iniciais são definidos o nome da classe ou interface, os métodos públicos (semelhante a como o Erlang define funções externas), heranças de superclasses, implementações de interfaces e métodos construtores, caso a classe defina um próprio construtor. Sempre que for necessário a uma classe possuir um ou mais métodos estáticos, que não necessitem da invocação de um objeto para serem executados, é utilizado o token class methods seguido de ponto antes de todos os métodos estáticos. É importante lembrar que, antes da definição dos métodos estáticos, deve-se definir os métodos não-estáticos, iniciados com o token methods seguido de ponto. Desta forma o compilador tem a ca-

44 Observações nais da sintaxe do ooerlang 24 pacidade de diferenciar os métodos estáticos dos não-estáticos. Em todas as declarações iniciais, é utilizado um hífen no início e um ponto no final de cada linha. É possível a uma classe em ooerlang implementar uma interface e estender uma superclasse ao mesmo tempo, assim como em Java. Para isso ser possível, basta usar nas declarações iniciais tanto o token implements quanto o token extends (um por linha). Uma importante característica na sintaxe do ooerlang é que, tanto na extensão, quanto na implementação, as classes estendidas e implementadas aparecem dentro de parênteses. Se a classe precisar estender ou implementar mais de uma classe ou interface, elas devem estar dentro de uma lista que esteja dentro dos parênteses. Se uma classe não define um construtor, o compilador do ooerlang define um construtor padrão para a referida classe. Este construtor é utilizado da seguinte forma: classe::new (). Portanto, o construtor padrão de uma classe chama-se new (). O fonte apresentado em mostra um trecho de uma classe chamada Main, com o exemplo prático da utilização de construtores padrão na instanciação de quatro (4) classes as quais não foram definidos construtores próprios. 1 -class(main). 2 -export([main/0]). 3 4 class_methods. 5 6 main() -> 7 Transp = transporte::new_(), 8 Aviao = aviao::new_(), 9 Navio = navio::new_(), 10 Onibus = onibus::new_(), 11 (...) Código 2.5.1: Exemplo de uma classe chamada Main em ooerlang Pode-se verificar nesta classe que existe apenas o método principal, chamado main, e que esta classe também não possui atributos. Para as quatro instanciações de diferentes tipos de objetos, mostradas nas linhas 7, 8, 9 e 10, é utilizado o construtor padrão. Percebese que, sempre que o construtor padrão for utilizado, não é passado nenhum parâmetro de entrada na instanciação do objeto. Os atributos de uma classe instanciada com um construtor padrão são inicializados com valores nulos.

45 Capítulo 3 Padrões de Projeto de Criação Neste capítulo são analisados os cinco (5) padrões de projeto de criação definidos por [Gamma et al., 1994]. Para cada um dos padrões de criação explicados, é estudado o exemplo prático utilizado no mesmo, sendo feitas comparações de implementações dos códigos-fonte em Java e ooerlang, das principais classes modeladas no respectivo exemplo. Esta análise comparativa visa verificar a extensão ooerlang no que diz respeito à sua utilização na implementação dos padrões de projeto de criação. 3.1 Conceitos Iniciais Padrões de projeto de criação abstraem o processo de instanciação [Gamma et al., 1994]. Desta forma, utilizando os padrões de criação, é possível criar sistemas que independem da criação, composição e representação dos diferentes objetos. Logo, torna-se menos trabalhoso estender ou fazer manutenção em um projeto que utilize algum ou vários padrões de criação em conjunto. Uma classe de um padrão de criação utiliza herança para variar a classe que é instanciada, ao passo que um objeto de um padrão de criação irá delegar a instanciação a outro objeto [Gamma et al., 1994]. É perceptível que a utilização dos padrões de criação torna-se necessária quando o sistema precisa ser desenvolvido utilizando principalmente a composição de objetos. Padrões de criação tornam-se importantes quando sistemas evoluem

46 Padrão Abstract Factory 26 passando a depender mais de composição de objetos do que herança de classes [Gamma et al., 1994]. De acordo com [Gamma et al., 1994], existem 5 (cinco) padrões de projetos de criação, sendo eles: Abstract Factory, Builder, Factory Method, Prototype e Singleton. Esta é a ordem em que os padrões são tratados, demonstrando a utilização dos mesmos com a extensão orientada a objetos do Erlang, ooerlang. Todos os códigos-fonte deste capítulo podem ser encontrados em [GitHub, 2008]. 3.2 Padrão Abstract Factory De acordo com sua definição, o Abstract Factory tem como objetivo Prover uma interface para criar famílias de objetos relacionados ou dependentes sem especificar suas classes concretas. [Gamma et al., 1994]. Este padrão tem como objetivo facilitar a utilização de famílias de objetos por meio de interfaces utilizadas para criação dos objetos especificados pelo usuário. O padrão Abstract Factory é recomendado e utilizado quando necessita-se de um projeto no qual haja independência entre a criação, composição e representação dos objetos em relação ao sistema como um todo. Além disso, pode ser usado quando um sistema puder ser configurado com uma de múltiplas famílias de produtos e também quando seja necessário prover uma biblioteca de produtos, necessitando revelar apenas suas interfaces e não suas implementações Exemplo utilizado para este padrão No exemplo que foi utilizado para implementar a aplicação na prática do padrão Abstract Factory, desenvolveu-se um sistema para gerenciar uma loja de pizzas. Este exemplo foi extraído de [Freeman et al., 2004]. Considera-se neste exemplo que existem duas franquias desta pizzaria, uma em Nova Iorque e outra em Chicago. Cada franquia possui os mesmos sabores de pizza, porém com ingredientes diferentes. Pode-se perceber que existem famílias de produtos neste cenário. Cada sabor de pizza vai possuir diferentes ingredientes, dependendo da franquia da loja de pizzas. Portanto, a

47 Padrão Abstract Factory 27 forma de utilizar o padrão Abstract Factory é decompondo a criação de cada objeto pizza em fábricas de ingredientes. Isto significa dizer que para cada sabor de pizza de Nova Iorque vai existir uma classe somente para a fábrica de ingredientes. O mesmo é válido para a franquia de pizzas de Chicago. Portanto, na modelagem em Java vai existir uma interface chamada PizzaIngredientFactory e as classes que irão implementar essas interfaces serão justamente as que funcionarão como fábricas de ingredientes de cada franquia da pizzaria, no caso NYPizzaIngredient- Factory (para os ingredientes das pizzas de Nova Iorque) e ChicagoPizzaIngredientFactory (para as pizzas de Chicago). Existem famílias de ingredientes para cada tipo de ingrediente. Os tipos de ingredientes são os seguintes: Veggies, que são os tipos de vegetais, Clams, para os tipos de ameijoas, Sauce para os tipos de molhos existentes, Cheese para os tipos de queijo, Pepperoni, no caso do pepperoni e Dough, para definir como vai ser a massa da pizza. Foram utilizados nomes específicos para as classes que representam as duas lojas da pizzaria. As franquias da pizzaria passaram a possuir os seguintes nomes: NewYorkPizzaStore e ChicagoPizzaStore. Os sabores de pizza de cada franquia, por sua vez, possuem os nomes: CheesePizza, VeggiePizza, ClamPizza e PepperoniPizza. Para entender melhor este cenário, a figura 3.1 mostra o diagrama de classes simplificado desta modelagem. As classes sobrepostas possuem implementação similar às classes que as sobrepõem. Desta forma é possível observar a utilização do padrão Abstract Factory na modelagem das franquias da loja de pizzas. Cada grupo de ingredientes foi modelado para possuir uma interface que é implementada pelos respectivos ingredientes Comparação das implementações em Java e ooerlang Conforme explicado anteriormente, cada tipo de ingrediente é modelado para ser uma interface a ser implementada por todos os respectivos ingredientes. Por exemplo, um tipo de ingrediente é o queijo, ou Cheese, portanto, vai haver uma interface chamada Cheese, e as classes que a irão implementar são os tipos de queijo, ou seja, MozzarellaCheese (queijo mussarela), ParmesanCheese (queijo parmesão) e ReggianoCheese (queijo parmesão reggiano).

48 Padrão Abstract Factory 28 Figura 3.1: Diagrama de classes do exemplo para o padrão Abstract Factory. Para comparar os fontes gerados, são verificadas as implementações da interface Cheese, tanto em Java quanto em ooerlang, analisando assim as principais diferenças entre ambas.

49 Padrão Abstract Factory 29 Verificamos no código 3.2.1, a implementação em Java desta interface, assim como no código a implementação similar em ooerlang. 1 public interface Cheese { 2 public String tostring(); 3 } Código 3.2.1: Interface Cheese em Java 1 -interface(cheese). 2 -export([to_string/0]). 3 4 methods. 5 6 to_string(). Código 3.2.2: Interface Cheese em ooerlang É possível observar pequenas diferenças de implementação entre ambas as abordagens. É evidente que a forma de escrita do ooerlang é bastante próxima e similar à do Java. Semelhante à essa interface, também existem as interfaces Pepperoni, Dough, Veggies, Clams e Sauce, conforme abordadas anteriormente. O padrão Abstract Factory permite que, por meio das classes ChicagoPizzaIngredientFactory e NYPizzaIngredientFactory, seja possível definir quais sabores pertencem às respectivas franquias. Eis a vantagem de utilizar este padrão. Dessa forma, as famílias de algoritmos tornam-se desacopladas do resto das implementações, tornando a inclusão de possíveis novos ingredientes uma tarefa menos impactante para o resto da modelagem. Os códigos e mostram as implementações da interface PizzaIngredientFactory em Java e ooerlang respectivamente. Esta interface é implementada pelas duas distintas franquias da pizzaria, NYPizzaIngredientFactory e ChicagoPizzaIngredientFactory. E são justamente estas implementações que definem os tipos de ingredientes para cada diferente tipo de sabor de pizza, de acordo com o sabor escolhido pelo cliente. A classe principal (que possui o método Main), é a classe PizzaTestDrive. Tanto em Java quanto em ooerlang, ambas possuem o mesmo comportamento. Os códigos e mostram a implementação desta classe em Java e ooerlang respectivamente. As

50 Padrão Abstract Factory 30 1 public interface PizzaIngredientFactory { 2 3 public Dough createdough(); 4 public Sauce createsauce(); 5 public Cheese createcheese(); 6 public Veggies[] createveggies(); 7 public Pepperoni createpepperoni(); 8 public Clams createclam(); 9 10 } Código 3.2.3: Interface PizzaIngredientFactory em Java 1 -interface(pizzaingredientfactory). 2 -export([create_dough/0, create_sauce/0, create_cheese/0]). 3 -export([create_veggies/0, create_pepperoni/0, create_clam/0]). 4 5 methods. 6 7 create_dough(). 8 create_sauce(). 9 create_cheese(). 10 create_veggies(). 11 create_pepperoni(). 12 create_clam(). Código 3.2.4: Interface PizzaIngredientFactory em ooerlang figuras 3.2 e 3.3 mostram a execução deste fonte, sendo dessa forma possível verificar e comparar o resultado de implementação das duas abordagens. Observam-se algumas diferenças na execução dos fontes em Java e ooerlang. Em Java a execução em linha de comando ocorre semelhante a qualquer outro programa. Já em ooerlang, é necessário primeiramente executar o programa Erlang, e em seguida chamar o método desejado passando a classe à qual este método pertence, de forma semelhante com a qual se chama uma função de um módulo em Erlang. Dessa forma, espera-se que este fonte execute similarmente ao fonte em Java. Verificando as implementações mostradas, observa-se uma grande semelhança entre as formas de sintaxe do Java e do ooerlang. Podemos aplicar este padrão em ooerlang da mesma forma que este padrão já é utilizado em Java. Quando se tem uma modelagem que possui diversas famílias de produtos, comportamentos ou características, este padrão poderá ser utilizado. A facilidade de implementação em ooerlang demonstra a flexibilidade desta extensão do

51 Padrão Builder 31 1 public class PizzaTestDrive { 2 3 public static void main(string[] args) { 4 PizzaStore nystore = new NYPizzaStore(); 5 PizzaStore chicagostore = new ChicagoPizzaStore(); 6 7 Pizza pizza = nystore.orderpizza("cheese"); 8 System.out.println("Ethan ordered a " + pizza + "\n"); 9 10 pizza = chicagostore.orderpizza("cheese"); 11 System.out.println("Joel ordered a " + pizza + "\n"); pizza = nystore.orderpizza("clam"); 14 System.out.println("Ethan ordered a " + pizza + "\n"); pizza = chicagostore.orderpizza("clam"); 17 System.out.println("Joel ordered a " + pizza + "\n"); pizza = nystore.orderpizza("pepperoni"); 20 System.out.println("Ethan ordered a " + pizza + "\n"); pizza = chicagostore.orderpizza("pepperoni"); 23 System.out.println("Joel ordered a " + pizza + "\n"); pizza = nystore.orderpizza("veggie"); 26 System.out.println("Ethan ordered a " + pizza + "\n"); pizza = chicagostore.orderpizza("veggie"); 29 System.out.println("Joel ordered a " + pizza + "\n"); 30 } 31 } Código 3.2.5: Classe principal PizzaTestDrive em Java Erlang para problemas que envolvam situações de acoplamento forte entre classes. Quando se necessite utilizar uma solução com o intuito de se obter uma modelagem desacoplada, para um problema de famílias de classes e subclasses, é possivel utilizar, da mesma forma que se realiza no Java, uma solução em ooerlang, resolvendo o problema similarmente. 3.3 Padrão Builder De acordo com sua definição, o padrão Builder tem por objetivo Separar a construção de um objeto complexo de sua representação, para que o mesmo processo de construção possa criar representações diferentes [Gamma et al., 1994]. Desta forma, a estrutura de construção do objeto estará encapsulada, ou seja, não visível ao usuário, estando disponível

52 Padrão Builder class(pizzatestdrive). 2 -export([main/0]). 3 4 class_methods. 5 6 main() -> 7 NyStore = nypizzastore::new_(), 8 ChicagoStore = chicagopizzastore::new_(), 9 10 Pizza1 = NyStore::order_pizza("cheese", nypizzastore), 11 io:format("ethan ordered a "), 12 Pizza1::to_string(nyPizzaStore), Pizza2 = ChicagoStore::order_pizza("cheese", chicagopizzastore), 15 io:format("joel ordered a "), 16 Pizza2::to_string(chicagoPizzaStore), Pizza3 = NyStore::order_pizza("clam", nypizzastore), 19 io:format("ethan ordered a "), 20 Pizza3::to_string(nyPizzaStore), Pizza4 = ChicagoStore::order_pizza("clam", chicagopizzastore), io:format("joel ordered a "), Pizza4::to_string(chicagoPizzaStore), Pizza5 = NyStore::order_pizza("pepperoni", nypizzastore), 27 io:format("ethan ordered a "), 28 Pizza5::to_string(nyPizzaStore), Pizza6 = ChicagoStore::order_pizza("pepperoni", chicagopizzastore), 31 io:format("joel ordered a "), 32 Pizza6::to_string(chicagoPizzaStore), Pizza7 = NyStore::order_pizza("veggie", nypizzastore), 35 io:format("ethan ordered a "), 36 Pizza7::to_string(nyPizzaStore), Pizza8 = ChicagoStore::order_pizza("veggie", chicagopizzastore), 39 io:format("joel ordered a "), 40 Pizza8::to_string(chicagoPizzaStore). Código 3.2.6: Classe principal PizzaTestDrive em ooerlang apenas a interface de construção dos referidos objetos. Usualmente, o padrão Builder é melhor aplicado em situações em que o algoritmo responsável por criar objetos complexos devem ser independentes das partes que constituem o objeto e a forma com que o mesmo é construído. Este padrão é também bastante utilizado quando o processo de construção deverá permitir diferentes representações do objeto que está sendo construído.

53 Padrão Builder 33 Figura 3.2: Execução do exemplo para o padrão Abstract Factory em Java Exemplo utilizado para este padrão No exemplo utilizado temos um cenário de construção de pizzas. Neste novo cenário apresentam-se dois tipos de pizza apenas, Hawaiian Pizza (pizza havaina) e Spicy Pizza (pizza apimentada). Neste exemplo, retirado de [Making, 2013], cada pizza possui uma quantidade certa de ingredientes, sendo que os ingredientes são distintos para ambos os sabores. De acordo com o padrão, dependendo do pedido do cliente, vai ser construída uma pizza do tipo havaiana ou apimentada. Mas em ambos os casos, será utilizada uma classe chamada Waiter, que faz o papel do construtor, estando separado na construção da representação dos objetos pizza existentes. Desta forma, ambos os sabores são construídos pelo mesmo processo, construíndo diferentes pizzas com diferentes ingredientes. A figura 3.4 mostra um diagrama simplificado deste exemplo para melhor entendimento do cenário.

54 Padrão Builder 34 Figura 3.3: Execução do exemplo para o padrão Abstract Factory em ooerlang. Sempre que um sabor de pizza for escolhido pelo usuário, o mesmo será criado por meio da classe Waiter. Esta classe irá primeiramente instanciar um objeto da classe Pizza, recebendo um tipo de pizza designada pelo usuário, utilizando em seguida um método chamado constructpizza, responsável por inserir e construir os ingredientes específicos para a pizza desejada. Este mesmo método de construção é utilizado para qualquer tipo de pizza, assim como será utilizado se houver inclusão de algum novo sabor de pizza Comparação das implementações em Java e ooerlang Verificando inicialmente a classe Pizza, tanto em Java quanto em ooerlang, observa-se que a mesma é uma classe que irá ser herdada pelos dois sabores de pizza definidos para o exemplo dado. Verifica-se também que cada pizza possui três (3) ingredientes principais, que são Dough (massa), Sauce (molho), e Toppings, referente aos ingredientes extras de cada pizza. Os códigos e mostram as respectivas implementações desta classe em Java e ooerlang.

55 Padrão Builder 35 Figura 3.4: Diagrama de classes do exemplo para o padrão Builder. 1 public class Pizza { 2 private String dough = ""; 3 private String sauce = ""; 4 private String topping = ""; 5 6 public void setdough(string dough) { this.dough = dough; } 7 public void setsauce(string sauce) { this.sauce = sauce; } 8 public void settopping(string topping) { this.topping = topping; } 9 10 public void showingredients() { 11 System.out.println("Ingredients: " + dough + ", 12 " + sauce + ", 13 " + topping); 14 } 15 } Código 3.3.1: Classe Pizza em Java A classe Waiter, conforme dito anteriormente, é responsável por iniciar a construção propriamente dita dos objetos do tipo Pizza. Esta classe deve iniciamente receber o tipo de pizza a ser construído, e em seguida procede na construção da mesma, inserindo os di-

56 Padrão Builder class(pizza). 2 -export([set_dough/1, set_sauce/1, set_topping/1, show_ingredients/0]). 3 4 attributes. 5 6 Dough; 7 Sauce; 8 Topping methods set_dough(dough) -> 13 self::dough = Dough set_sauce(sauce) -> 16 self::sauce = Sauce set_topping(topping) -> 19 self::topping = Topping show_ingredients() -> 22 io:format("ingredients: ~p, ~p, ~p~n", 23 [self::dough, self::sauce, self::topping]). Código 3.3.2: Classe Pizza em ooerlang ferentes tipos de sabores em cada pizza, por meio dos métodos createnewpizzaproduct(), builddough(), buildsauce() e buildtopping(). Os códigos e mostram com mais detalhes estas implementações. 1 public class Waiter { 2 private PizzaBuilder pizzabuilder; 3 4 public void setpizzabuilder(pizzabuilder pb) { pizzabuilder = pb; } 5 public Pizza getpizza() { return pizzabuilder.getpizza(); } 6 7 public void constructpizza() { 8 9 pizzabuilder.createnewpizzaproduct(); pizzabuilder.builddough(); 10 pizzabuilder.buildsauce(); 11 pizzabuilder.buildtopping(); 12 } 13 } Código 3.3.3: Classe Waiter em Java A classe principal, BuilderExample, demonstra uma forma com a qual o exemplo pode ser utilizado. São instanciados dois tipos de pizza, cada um para um diferente sabor. Para

57 Padrão Builder class(waiter). 2 -export([set_pizza_builder/1, get_pizza/0, construct_pizza/0]). 3 4 attributes. 5 6 PizzaBuilder. 7 8 methods set_pizza_builder(pb) -> 11 self::pizzabuilder = Pb get_pizza() -> Temp = self::pizzabuilder, 15 Return = Temp::get_pizza(), 16 Return construct_pizza() -> 19 Temp = self::pizzabuilder, 20 Temp::create_new_pizza_product(), 21 Temp::build_dough(), 22 Temp::build_sauce(), 23 Temp::build_topping(). Código 3.3.4: Classe Waiter em ooerlang cada construção da pizza é utilizada uma instanciação da classe Waiter, sendo que a diferenciação nas construções, ou seja, os sabores de cada pizza estão encapsulados para o usuário. As construções de cada específico sabor são chamados pela classe Waiter. Conforme pode ser observado nos códigos e 3.3.6, as implementações em Java e ooerlang, respectivamente, são bastante semelhantes. Na sintaxe do ooerlang, muitas características do Erlang estão presentes, com algumas diferenças que são específicas da extensão do Erlang para utilização da orientação à objetos nesta linguagem. Em Java não existem dificuldades de entendimento, pois a sintaxe já é bastante conhecida, com a ressalva de estar sendo utilizada na implementação de um padrão de projeto. As figuras 3.5 e 3.6 mostram a execução do exemplo do padrão Builder nas implementações feitas em Java e ooerlang respectivamente. Conforme já foi dito anteriormente, inicialmente é instanciado e construído um objeto do tipo HawaiianPizza, em seguida, o mesmo procedimento é realizado para um objeto do tipo SpicyPizza. Ambos tem construção similar, porém resultados diferentes. Verificou-se que é possível a implementação e a execução de um exemplo que se utiliza

58 Padrão Builder 38 1 public class BuilderExample { 2 public static void main(string[] args) { 3 Waiter waiter = new Waiter(); 4 PizzaBuilder hawaiianpizzabuilder = 5 new HawaiianPizzaBuilder(); 6 PizzaBuilder spicypizzabuilder = 7 new SpicyPizzaBuilder(); 8 9 System.out.println("Preparing to build Hawaiian Pizza..."); 10 waiter.setpizzabuilder( hawaiianpizzabuilder ); 11 waiter.constructpizza(); Pizza pizza1 = waiter.getpizza(); System.out.println(hawaiianPizzaBuilder); 15 pizza1.showingredients(); System.out.println("\nPreparing to build Spicy Pizza..."); 18 waiter.setpizzabuilder(spicypizzabuilder); 19 waiter.constructpizza(); Pizza pizza2 = waiter.getpizza(); 22 System.out.println(spicyPizzaBuilder); } pizza2.showingredients(); 25 } Código 3.3.5: Classe principal BuilderExample em Java do padrão Builder em ooerlang, obtendo, assim, um resultado semelhante ao obtido com a execução do mesmo exemplo implementado em Java. A extensão ooerlang mostrou-se apta a realizar uma implementação similar e com os mesmos resultados que já tinham sido verificados em Java. Na utilização deste padrão, é possível variar a representação interna de um produto, neste caso a pizza. Dependendo do sabor escolhido, os tipos de ingredientes variam. Eles são a representação interna do objeto neste exemplo. A interface deste padrão é responsável por esconder a estrutura interna do produto, no caso, os objetos do tipo pizza. Desta forma a construção e a representação dos produtos foram isoladas, com o encapsulamento do processo de construção das pizzas.

59 Padrão Factory Method class(builderexample). 2 -export([main/0]). 3 4 class_methods. 5 6 main() -> 7 Waiter = waiter::new_(), 8 HawaiianPizzaBuilder = hawaiianpizzabuilder::new_(), 9 SpicyPizzaBuilder = spicypizzabuilder::new_(), io:format(" Preparing to build Hawaiian Pizza...~n"), 12 Waiter::set_pizza_builder(HawaiianPizzaBuilder), 13 Waiter::construct_pizza(), Pizza1 = Waiter::get_pizza(), 16 io:format("~p ", [HawaiianPizzaBuilder::to_string()]), 17 Pizza1::show_ingredients(), io:format("~n Preparing to build Spicy Pizza...~n"), 20 Waiter::set_pizza_builder(SpicyPizzaBuilder), 21 Waiter::construct_pizza(), Pizza2 = Waiter::get_pizza(), io:format("~p ", [SpicyPizzaBuilder::to_string()]), 25 Pizza2::show_ingredients(). Código 3.3.6: Classe principal BuilderExample em ooerlang 3.4 Padrão Factory Method De acordo com sua definição inicial, o padrão Factory Method tem como objetivo: Definir uma interface para criar um objeto mas deixar que subclasses definam que classe instanciar. Factory Method permite que uma classe delegue a responsabilidade de instanciamento às subclasses [Gamma et al., 1994]. Factory Method pode ser confundido com o padrão Abstract Factory, mas sua diferença está no fato de delegar a instanciação dos objetos diretamente para as subclasses. Este padrão pode ser bem aplicado a situações e problemas em que uma classe não pode antecipar que tipo de objetos deve criar, assim como precisa delegar às subclasses a responsabilidade de especificar os objetos que serão instanciados. O padrão Factory Method também permite, dependendo dos objetivos da implementação, que seja possível localizar a subclasse que irá ser a responsável por instanciar determinado objeto.

60 Padrão Factory Method 40 Figura 3.5: Execução do exemplo para o padrão Builder em Java Exemplo utilizado para este padrão No exemplo que foi implementado para este padrão, retirado de [Freeman et al., 2004], houve novamente uma implementação de uma pizzaria. Neste caso, o cenário é parecido com o utilizado no padrão Abstract Factory, com a diferença de que é menos complexo, pois não existem as famílias de ingredientes para cada sabor diferente de pizza, apesar de mesmos sabores de pizzas em franquias diferentes possuírem ingredientes diferentes. A pizzaria possui ainda suas duas franquias de pizza, uma em Nova Iorque, representada pela classe NYPizzaStore e outra em Chicago, representada pela classe ChicagoPizzaStore. A idéia central é a de não instanciar os objetos representando cada sabor de pizza de diferentes franquias diretamente, e sim utilizar uma classe intermediária que receberá o tipo de pizza a ser instanciada e criada, assim como a franquia da qual a mesma pertence para que este objeto possa ser criado pelas subclasses referentes ao sabor selecionado.

61 Padrão Factory Method 41 Figura 3.6: Execução do exemplo para o padrão Builder em ooerlang. Portanto, para este exemplo existe uma classe chamada PizzaStore, que possui a interface necessária para que se possa criar qualquer sabor de pizza desejado, por meio do método abstrato createpizza(). Este método é implementado em duas outras subclasses, chamadas NYPizzaStore (relacionada com os sabores de pizza de Nova Iorque) e Chicago- PizzaStore (para criar os sabores de Chicago). Portanto, sempre a criação de cada pizza vai ser solicitada na classe principal, PizzaTestDrive, que, por sua vez, repassa esta responsabilidade de criação às subclasses. Existe também a classe Pizza, que possui todos os atributos e métodos, representando genericamente cada objeto pizza a ser criado. Nesta modelagem é possível perceber que o código sujeito a modificações é isolado do código que não muda. Os métodos da classe Pizza por exemplo, que não são passíveis de modificação, estão separados dos tipos de pizza, que podem modificar-se com o tempo (sabores podem ser incluídos e retirados com o tempo). A figura 3.7 mostra um diagrama de classes simplificado para melhor entendimento do cenário. Pode-se observar que as classes NYPizzaStore e ChicagoPizzaStore herdam os métodos da classe PizzaStore, que no caso, representa a pizzaria como um todo. As subclasses

62 Padrão Factory Method 42 Figura 3.7: Diagrama de classes do exemplo para o padrão Factory Method. são as franquias desta pizzaria, cada uma com suas características diferentes de sabores. Cada subclasse possui o método createpizza, responsável por iniciar a criação da pizza propriamente dita Comparação das implementações em Java e ooerlang Tanto em Java quanto em ooerlang, a mesma estrutura foi criada, de acordo com o diagrama de classes simplificado mostrado na figura 3.7. Verificando o fonte da classe PizzaStore, conforme os códigos em e que mostram as implementações em Java e ooerlang respectivamente, verifica-se que a criação da pizza é repassada para as subclasses

63 Padrão Factory Method 43 enquanto que o preparo permanece nesta classe. 1 public abstract class PizzaStore { 2 3 abstract Pizza createpizza(string item); 4 5 public Pizza orderpizza(string type) { 6 Pizza pizza = createpizza(type); 7 System.out.println("--- Making a " + pizza.getname() + " ---"); 8 pizza.prepare(); 9 pizza.bake(); 10 pizza.cut(); 11 pizza.box(); 12 return pizza; } } Código 3.4.1: Classe PizzaStore em Java 1 -class(pizzastore). 2 -export([create_pizza/1, order_pizza/2]). 3 4 methods. 5 6 create_pizza(item) -> null. 7 8 order_pizza(type, String) -> 9 Object = {String, ObjectID}, 10 Pizza = Object::create_pizza(Type), io:format("--- Making a ~p --- ~n", [Pizza::get_name()]), 13 Pizza::prepare(), 14 Pizza::bake(), 15 Pizza::cut(), 16 Pizza::box(), 17 Pizza. Código 3.4.2: Classe PizzaStore em ooerlang Desta forma o código que não é sujeito a modificações, permanece isolado do código que pode modificar-se com o tempo. A classe Pizza possui as implementações dos métodos que tratam dos procedimentos para finalização do processo de construção da pizza, mas isto ocorre apenas depois da pizza de fato já ter recebido seus ingredientes. Os códigos e mostram a implementação da classe Pizza em Java e ooerlang, respectivamente. Existem algumas diferenças próprias entre as sintaxes do Java e ooerlang, porém a utilização dos atributos e dos métodos é a mesma. As classes NYPizzaStore e Chicago-

64 Padrão Factory Method 44 1 public abstract class Pizza { 2 String name; 3 String dough; 4 String sauce; 5 ArrayList toppings = new ArrayList(); 6 7 void prepare() { 8 System.out.println("Preparing " + name); 9 System.out.println("Tossing dough..."); 10 System.out.println("Adding sauce..."); 11 System.out.println("Adding toppings: "); 12 for (int i = 0; i < toppings.size(); i++) { } System.out.println(" " + toppings.get(i)); 15 } void bake() { 18 System.out.println("Bake for 25 minutes at 350"); 19 } void cut() { 22 System.out.println("Cutting the pizza into diagonal slices"); 23 } void box() { 26 System.out.println("Place pizza in official PizzaStore box"); 27 } Código 3.4.3: Classe Pizza em Java PizzaStore são similares em suas implementações, com a diferença de que cada uma trata dos sabores para suas próprias lojas. Cada franquia possui os mesmos sabores sendo que, o que diferencia os sabores de uma loja para a outra são os ingredientes utilizados para o preparo das pizzas. Os códigos e mostram as respectivas implementações em Java e ooerlang da classe NYPizzaStore. Na execução deste exemplo é utilizada a classe PizzaTestDrive. Nesta classe, são inicialmente criadas instâncias das classes NYPizzaStore e ChicagoPizzaStore, para que sejam as responsáveis por tratar dos pedidos dos clientes de pizza. Em seguida são instanciadas várias pizzas, para vários sabores de pizza nas duas franquias da pizzaria. O método utilizado para iniciar o preparo das pizzas, conforme já visto anteriormente, é o orderpizza(), que recebe como parâmetro o sabor da pizza a ser feita. A franquia que irá preparar a referida pizza é justamente o objeto da classe desta franquia que já foi previamente instanciado. Se, por exemplo, uma pizza de queijo (Che-

65 Padrão Factory Method class(pizza). 2 -export([prepare/0, bake/0, cut/0, box/0, get_name/0]). 3 4 attributes. 5 6 Name; 7 Dough; 8 Sauce; 9 Toppings methods prepare() -> io:format("preparing ~p ~n", [self::name]), 15 io:format("tossing dough... ~n"), 16 io:format("adding Sauce... ~n"), 17 io:format("adding toppings: ~n"), 18 Tops = self::toppings, 19 prepare_aux(tops) prepare_aux([]) -> null; 22 prepare_aux([top Toppings]) -> io:format(" ~p~n", [Top]), prepare_aux(toppings) bake() -> 27 io:format("bake for 25 minutes at 350 ~n") cut() -> 30 io:format("cutting the pizza into diagonal slices ~n") box() -> 33 io:format("place pizza in official PizzaStore box ~n"). Código 3.4.4: Classe Pizza em ooerlang esepizza) da franquia de Nova Iorque precisar ser preparada, então a instância da classe NYPizzaStore irá chamar o método orderpizza( cheese ), onde o sabor da referida pizza é passado como parâmetro. As figuras 3.8 e 3.9 mostram a execução em Java e ooerlang deste exemplo. A utilização do padrão Factory Method em ooerlang mostrou-se com resultados satisfatórios, uma vez que foi possível de ser implementada, assim como sua execução mostrou semelhante resultado. A comprovação experimental da execução igual em Java e em ooerlang valida esta extensão do Erlang para ser utilizada em situações nas quais este padrão precise ser utilizado. Na utilização deste padrão, percebe-se que o código trata de forma bem definida a

66 Padrão Factory Method 46 1 public class NYPizzaStore extends PizzaStore { Pizza createpizza(string item) { if (item.equals("cheese")) { 5 return new NYStyleCheesePizza(); 6 } else if (item.equals("veggie")) { 7 return new NYStyleVeggiePizza(); 8 } else if (item.equals("clam")) { 9 return new NYStyleClamPizza(); 10 } else if (item.equals("pepperoni")) { 11 return new NYStylePepperoniPizza(); 12 } else return null; } } 1 -class(nypizzastore). 2 -extends(pizzastore). 3 -export([create_pizza/1]). 4 5 methods. 6 Código 3.4.5: Classe NYPizzaStore em Java 7 8 create_pizza(item) -> if 9 (Item == "cheese") -> 10 Pizza = nystylecheesepizza::new(), 11 Pizza; 12 (Item == "veggie") -> 13 Pizza = nystyleveggiepizza::new(), 14 Pizza; 15 (Item == "clam") -> 16 Pizza = nystyleclampizza::new(), Pizza; (Item == "pepperoni") -> 19 Pizza = nystylepepperonipizza::new(), 20 Pizza; 21 true -> 22 null 23 end. Código 3.4.6: Classe NYPizzaStore em ooerlang interface de utilização do cliente, assim como pode trabalhar com qualquer objeto concreto definido pelo usuário. Criar um objeto dentro de uma classe utilizando este padrão é uma solução geralmente mais flexível do que criar um objeto diretamente.

67 Padrão Prototype 47 Figura 3.8: Execução do exemplo para o padrão Factory Method em Java. 3.5 Padrão Prototype Segundo sua definição, este padrão tem por objetivo Especificar os tipos de objetos a serem criados usando uma instância como protótipo e criar novos objetos ao copiar este protótipo [Gamma et al., 1994]. Isto significa dizer que este padrão tem como objetivo principal facilitar a criação de novos objetos, em situações onde a instanciação simples de novos objetos de determinada classe seja demasiado custosa ou complexa para o sistema como um todo. Este padrão pode ser utilizado quando temos um sistema que deve ser independente de como seus produtos são criados, compostos e representados. Também pode ser usado quando as classes a serem instanciadas são especificadas em tempo de execução, ou quando as instâncias de uma classe podem possuir apenas pequenas combinações de estados diferentes. Neste caso é mais conveniente criar alguns protótipos para estes estados, clonando-os

68 Padrão Prototype 48 Figura 3.9: Execução do exemplo para o padrão Factory Method em ooerlang. ao invés de instanciar os objetos Exemplo utilizado para este padrão O exemplo utilizado foi retirado de [Eriksson, 2013], tratando-se de uma aplicação em que dois tipos de objetos podem ser intanciados: Cachorros (Dog), e Pessoas (Person). Neste exemplo foi utilizada uma interface chamada Prototype, responsável por possuir o método que realiza o processo de criar um novo objeto com as mesmas características de um objeto já existente, seja ele um cachorro ou uma pessoa. Dessa forma, caso seja necessário criar vários objetos do tipo cachorro, assim como criar vários objetos do tipo pessoa, com pequenas diferenças de características entre eles, ou seja, com poucas variações, é possível fazer isso apenas instanciando os tipos básicos, e em seguida pode-se realizar a clonagem deles para que se tenha um processo de criação de objetos mais simplificado, utilizando-se dos protótipos existentes. A figura 3.10 mostra um diagrama de classes simplificado para melhor entendimento deste exemplo. Portanto, é possível observar que existem duas classes principais, Dog e Person. Cada classe possui, para simplificação do exemplo e facilidade na compreensão, uma característica

69 Padrão Prototype 49 Figura 3.10: Diagrama de classes do exemplo para o padrão Prototype. singular. No caso da classe Dog, essa característica é o som de seu latido. Em relação à classe Person, a característica é o nome da referida pessoa. Então cada objeto da classe Dog vai possuir um som de latido específico, assim como cada objeto da classe Person vai possuir um nome próprio Comparação das implementações em Java e ooerlang Tanto na implementação deste exemplo em Java quanto em ooerlang, foram utilizadas quatro (4) classes: Dog e Person, que são as classes referentes aos tipos diferentes de objetos, Prototype, interface que possui o método responsável por clonar objetos na criação de novos objetos e a classe Demo, tratando-se da classe principal deste exemplo, possuindo o método Main(). As classes Dog e Person são similares em suas implementações, sendo que possuem o método construtor para instanciar novas classes e um método necessário para criar novas instâncias clonando as características de um objeto já existente, ou seja, construindo um

70 Padrão Prototype 50 novo objeto utilizando-se de características de outro objeto. É dessa forma que o padrão Prototype é utilizado. Os códigos e mostram as implementações da classe Person em Java e ooerlang, respectivamente. 1 public class Person implements Prototype { 2 3 String name; 4 5 public Person(String name) { 6 this.name = name; 7 } public Prototype doclone() { return new Person(name); 11 } public String tostring() { 14 return "This person is named " + name; 15 } 16 } Código 3.5.1: Classe Person em Java 1 -class(person). 2 -implements(prototype). 3 -export([new/1, do_clone/0, to_string/0]). 4 -constructor([new/1]). 5 6 attributes. 7 8 Name methods new(name) -> 13 self::name = Name do_clone() -> 16 person::new(self::name) to_string() -> 19 String = "This person is named " ++ self::name, 20 String. Código 3.5.2: Classe Person em ooerlang Pode ser verificado nas implementações mostradas em e a semelhança entre as sintaxes das referidas linguagens, sendo que cada uma utiliza suas características

71 Padrão Prototype 51 próprias. A interface Prototype possui o método doclone(), referente ao método que trata de utilizar objetos já existentes como protótipos para criação de novos objetos de forma menos complexa. Os códigos e mostram, respectivamente, as implementações em Java e ooerlang da interface Prototype. 1 public interface Prototype { 2 3 public Prototype doclone(); 4 5 } Código 3.5.3: Interface Prototype em Java 1 -interface(prototype). 2 -export([do_clone/0]). 3 4 methods. 5 6 do_clone(). Código 3.5.4: Interface Prototype em ooerlang Percebe-se então que sempre que um objeto precise ser criado, e que o mesmo objeto possui características de outro que já foi anteriormente instanciado, o objeto já instanciado pode ser utilizado como um protótipo para a criação do novo objeto, fazendo com que o novo objeto seja construído já possuindo as características principais do protótipo em questão. Dessa forma não será necessário ter todo o trabalho de configurar um novo objeto, dependendo da situação. A utilização de protótipos facilita o trabalho de reutilização de objetos na criação de novos objetos. Na execução deste exemplo, são instanciados dois objetos, um para cada classe (Dog e Person). Em seguida, para cada um destes novos objetos criados é criado um outro objeto, utilizando-se destes primeiros como protótipos, ou seja, os novos objetos criados passam a ter as características principais dos objetos já criados. Isto é possível devido à utilização do método responsável por clonar objetos utilizando outros objetos como protótipos na classe Prototype. As figuras 3.11 e 3.12 mostram a execução deste exemplo em Java e ooerlang. Verifica-se, observando a execução destes exemplos, que tanto em Java quanto em ooerlang os resultados foram os mesmos. Os objetos inicialmente criados possuem cada

72 Padrão Prototype 52 Figura 3.11: Execução do exemplo para o padrão Prototype em Java. um suas características próprias, e os objetos originados com base nos objetos já existentes, mostraram um comportamento semelhante ao apresentado por seus protótipos. A extensão do Erlang, ooerlang mostrou-se apta a implementar este exemplo que possui a síntese de utilização do padrão Prototype, em uma aplicação simples e eficiente. Verificase que, assim como o Java, o ooerlang pode ser utilizado para dar suporte a sistemas orientados a objetos com a facilidade de utilização deste padrão de projetos, por possuir as características principais do paradigma orientado a objetos. Algumas características podem ser notadas na utilização deste padrão de projetos. Dependendo da aplicação na qual o mesmo seja utilizado, é possível adicionar e remover novos objetos em tempo de execução, assim como é viável especificar novos objetos apenas variando seus valores e características. Na utilização deste padrão também pode-se reduzir a quantidade de subclasses, paralelizando a hierarquia de classes de objetos assim

73 Padrão Singleton 53 Figura 3.12: Execução do exemplo para o padrão Prototype em ooerlang. como configurar uma aplicação com classes de forma dinâmica. Estas características foram documentadas em [Gamma et al., 1994], no padrão Prototype. 3.6 Padrão Singleton A definição deste padrão pode ser escrita da seguinte forma: Garantir que uma classe só tenha uma única instância, e prover um ponto de acesso global a ela [Gamma et al., 1994]. Desta forma pode-se verificar que o padrão de projetos Singleton é necessário e aplicável em situações onde seja importante possuir apenas uma instância de determinada classe, evitando assim erros de inconsistência de dados, dependendo do sistema que estiver sendo modelado. Pode-se então afirmar que o padrão Singleton deve ser aplicado a sistemas na situação em que precise haver exatamente uma única instância de uma classe, sendo que esta instância deve ser acessível para os usuários por meio de um ponto de acesso bem conhecido. Outra situação em que este padrão pode ser utilizado é quando a única instância precisa ser estendida por subclasses, permitindo aos usuários utilizar a instância estendida sem

74 Padrão Singleton 54 que seja necessário modificar seu código Exemplo utilizado para este padrão No exemplo utilizado para aplicação deste padrão, retirado de [Freeman et al., 2004], foi modelado um sistema para gerenciamento de uma fábrica que produz chocolates. A característica principal desta fábrica é a de que existe uma e apenas uma caldeira para realizar o derretimento e o preparo do chocolate a ser produzido. Isto significa dizer que deve-se considerar as ações de fabricação em relação à caldeira, tendo a mesma como referência. Para se inserir matéria prima nesta caldeira, é necessário verificar se a mesma está vazia. Para se retirar chocolate derretido desta caldeira, deve-se primeiramente verificar se esta caldeira possui chocolate. Ou seja, para a modelagem a ser utilizada, é necessário que exista apenas uma única instância da caldeira desta fábrica, sendo que a mesma deve possuir um único ponto de acesso global, evitando problemas de fabricação. A figura 3.13 mostra, para melhor entendimento, um diagrama de classes desta modelagem. Figura 3.13: Diagrama de classes do exemplo para o padrão Singleton. Observa-se que esta modelagem possui apenas duas classes, a classe ChocolateControl-

75 Padrão Singleton 55 ler, que possui o método principal, e de onde o exemplo é executado, e a classe Chocolate- Boiler, responsável por possuir em um de seus atributos o atributo uniqueinstance. Esta é a única instância referente à caldeira da fábrica de chocolates explicada anteriormente. Os métodos da classe ChocolateBoiler permitem ao cliente encher, esvaziar e acender a fornalha da caldeira (fill(), drain() e boil() respectivamente), além outros dois métodos responsáveis por verificar o estado atual da caldeira, caso a mesma esteja vazia ou cheia (isempty() e isboiled()). Desta forma, quando se vai encher a caldeira, deve-se verificar se a mesma já não está cheia, e vice-versa. Verifica-se então a necessidade de haver apenas uma única instância para a caldeira, assim como apenas um ponto de acesso global a este objeto. Desta forma, se dois objetos tentarem acessar a caldeira ao mesmo tempo, não vão haver problemas de inconsistências e de erros de execução. É necessário portanto que haja um método específico para que se obtenha o ponto de acesso global a esta caldeira, e este método está implementado na classe ChocolateBoiler, e chama-se getinstance() Comparação das implementações em Java e ooerlang As classes ChocolateController e ChocolateBoiler são implementadas em Java e ooerlang de acordo com suas características próprias. Em Java, na classe ChocolateBoiler, o método responsável por retornar o único ponto de acesso é implementado utilizando-se de um atributo estático, e dessa forma, sempre que seja necessário acessar este objeto, é verificado se o atributo já foi instanciado, criando-o em caso negativo e retornando-o em caso positivo. O código mostra essa implementação em Java. Em ooerlang esta implementação também foi realizada, porém com algumas diferenças. Enquanto que em Java é possivel utilizar-se de atributos estáticos, em ooerlang isto não é possível. A solução seguida foi a de se utilizar processos registrados. Todo objeto em ooerlang é um processo. A instância única também o é. Dessa forma o método para retornar o ponto de acesso verifica se o atributo da instância única já foi registrado ou não, sendo criado e registrado em caso negativo e apenas retornado em caso positivo. O código mostra esta implementação em ooerlang. Em relação à classe ChocolateController, que foi, igualmente, implementada em Java e

76 Padrão Singleton 56 1 public class ChocolateBoiler { 2 private boolean empty; 3 private boolean boiled; 4 private static ChocolateBoiler uniqueinstance; 5 6 private ChocolateBoiler() { 7 empty = true; 8 boiled = false; 9 } public static ChocolateBoiler getinstance() { 12 if (uniqueinstance == null) { System.out.println("Creating unique instance of Chocolate Boiler"); 15 uniqueinstance = new ChocolateBoiler(); 16 } 17 System.out.println("Returning instance of Chocolate Boiler"); 18 return uniqueinstance; 19 } Código 3.6.1: Classe ChocolateBoiler em Java ooerlang, esta é a classe principal, e seu objetivo é o de testar a implementação verificando a execução do fonte, e se cria apenas uma única instância com um ponto de acesso global a ela. Então é utilizado o método getinstance(), são realizadas algumas operações na caldeira e em seguida um outro objeto tenta ter acesso à instância, verificando se receberá a mesma instância criada anteriormente. Os códigos em e referem-se a esta classe em Java e ooerlang, respectivamente. Ao executar o método main() de ambas as implementações, verifica-se que seus resultados mostram inicialmente a instanciação da instância única relativa à caldeira da fábrica de chocolates, utilização de alguns métodos e, em seguida novamente a utilização do método getinstance(), verificando se, em ambos os casos, a mesma instância criada anteriormente é utilizada. As figuras 3.14 e 3.15 mostram o resultado da execução deste exemplo em Java e ooerlang. Observa-se, na implementação do exemplo referente ao padrão Singleton em ooerlang, uma diferença em relação à implementação em Java. Enquanto que em Java é possível criar variáveis estáticas, em ooerlang isto não é utilizável, portanto é necessário utilizar outra ferramenta bastante conhecida em Erlang que, por consequência, também está presente em ooerlang. Trata-se da utilização de processos registrados. Especificamente no exemplo do padrão Singleton em ooerlang, é necessário utilizar-

77 Padrão Singleton class(chocolateboiler). 2 -export([new/0, get_instance/0, fill/0, drain/0, boil/0]). 3 -export([is_empty/0, is_boiled/0]). 4 -constructor([new/0]). 5 6 attributes. 7 8 Empty; 9 Boiled; 10 UniqueInstance methods get_instance() -> 15 ListOfProcesses = erlang:registered(), 16 Return = lists:member(unique_instance, ListOfProcesses), 17 if 18 (Return == false) -> 19 io:format("creating unique instance of 20 Chocolate Boiler ~n"), 21 self::uniqueinstance = chocolateboiler::new(), 22 erlang:register(unique_instance, ObjectID); true -> io:format("") 25 end, 26 io:format("returning instance of Chocolate Boiler ~n"), 27 Unique = {chocolateboiler, whereis(unique_instance)}, 28 Unique::UniqueInstance. Código 3.6.2: Classe ChocolateBoiler em ooerlang 1 public class ChocolateController { 2 public static void main(string args[]) { 3 ChocolateBoiler boiler = ChocolateBoiler.getInstance(); 4 boiler.fill(); 5 boiler.boil(); 6 boiler.drain(); 7 8 // will return the existing instance 9 ChocolateBoiler boiler2 = ChocolateBoiler.getInstance(); 10 } 11 } Código 3.6.3: Classe principal ChocolateController em Java se de processos registrados na criação da instância relativa à caldeira. Desta forma é possível obter um ponto de acesso global único a esta instância. Na primeira instanciação, é realizado o registro do referente processo. Nas outras tentativas de obter a instância única, verifica-se que este processo já foi registrado, retornando-se apenas a instância única

78 Padrão Singleton class(chocolatecontroller). 2 -export([main/0]). 3 4 class_methods. 5 6 main() -> 7 Boiler = chocolateboiler::new(), 8 Boiler::get_instance(), 9 Boiler::fill(), 10 Boiler::boil(), 11 Boiler::drain(), Boiler2 = chocolateboiler::new(), 14 Boiler2::get_instance(). Código 3.6.4: Classe principal ChocolateController em ooerlang Figura 3.14: Execução do exemplo para o padrão Singleton em Java. necessária. Assim consegue-se utilizar o padrão Singleton em ooerlang. Algumas consequências na utilização deste padrão podem ser verificadas, como por

79 Conclusões dos Padrões de Projeto de Criação em ooerlang 59 Figura 3.15: Execução do exemplo para o padrão Singleton em ooerlang. exemplo, acesso controlado a uma única instância, facilidade de refinamento de operações quando a classe única for herdada por subclasses, permissão na utilização de um número variado de instâncias dependendo das características próprias do sistema. 3.7 Conclusões dos Padrões de Projeto de Criação em ooerlang Os padrões de projeto de criação, conforme demonstrado pelos exemplos utilizados, de uma forma geral, possuem a característica principal de abstrair o processo de instanciação. Duas principais abordagens podem ser observadas na utilização dos padrões de criação. Em uma delas o encapsulamento está relacionado com as classes concretas que um sistema realmente utiliza. A outra abordagem tem por objetivo encapsular as instâncias destas classes concretas e as relações entre as mesmas. Nas implementações dos exemplos utilizados para os padrões de criação, muitas das características de implementação utilizadas nos fontes em Java são, semelhantemente, uti-

80 Conclusões dos Padrões de Projeto de Criação em ooerlang 60 lizadas em ooerlang. É importante notar, entretanto, que no exemplo do padrão de projetos Singleton, é utilizada uma característica própria do Erlang também presente no ooerlang, a de nomeação de processos. Uma vez que no ooerlang não é possivel criar variáveis estáticas, as mesmas podem ser substituídas por processos registrados e nomeados. Todos os cinco (5) padrões de criação implementados em ooerlang de acordo com os fontes usados como referência em Java apresentam comportamento similar quando executado após terem sido compilados por meio do compilador do ooerlang. A quantidade de classes implementadas tanto em Java quanto em ooerlang é a mesma, ou seja, ao se utilizar do ooerlang, não é necessário criar uma quantidade diferente de classes presentes nas implementações em Java.

81 Capítulo 4 Padrões de Projeto Estruturais No presente capítulo são analisados os sete (7) padrões de projetos do tipo estrutural. Estes padrões foram inicialmente definidos por [Gamma et al., 1994], sendo estudados em suas características próprias e em suas diferentes formas de aplicação, com a ajuda de exemplos práticos para cada um dos padrões estruturais abordados. Alguns códigos-fontes são apresentados para ilustrar melhor os exemplos, assim como para comparar a sintaxe do Java com a extensão ooerlang, verificando os resultados obtidos nas execuções dos exemplos utilizados. 4.1 Conceitos Iniciais Padrões Estruturais se preocupam em como as classes e objetos são compostos para formar largas estruturas [Gamma et al., 1994]. Todos os padrões de projetos que fazem parte desta classificação possuem alguma característica própria bem definida, relacionada com as estruturas de relação entre as classes pertencentes à modelagem de determinado sistema. Seu foco é na solução de algum problema estrutural, e também relacional entre as referidas classes e interfaces do modelo em questão. Uma vantagem que pode ser verificada na utilização dos padrões de projetos estruturais é, por exemplo, a possibilidade de resolver problemas que envolvam duas bibliotecas de classes que foram desenvolvidas inicialmente de forma isolada, fazendo com que possam

82 Padrão Adapter 62 trabalhar em conjunto. Outra vantagem é quando deve-se adaptar a interface de uma classe para outra classe que, a priori, não pertence ao projeto original. Esta abordagem é bastante utilizada, sendo fácil encontrar situações nas quais os padrões estruturais podem ser aplicados. Os padrões de projetos estruturais, apesar de serem diferentes entre si, no que diz respeito ao problema que visam resolver, não são mutuamente exclusivos. Isto significa afirmar que podem existir situações em que seja recomendado, ou até mesmo necessário utilizar mais de um padrão de projeto simultaneamente. Em muitos casos estes padrões se complementam, dependendo do sistema a ser modelado. Muitos padrões de projetos estruturais estão relacionados em algum grau [Gamma et al., 1994]. Todos os códigos-fonte deste capítulo podem ser encontrados em [GitHub, 2008]. 4.2 Padrão Adapter Verificando-se sua definição inicial observa-se que o padrão Adapter tem por objetivo: Converter a interface de uma classe em outra interface esperada pelos clientes. Adapter permite a comunicação entre classes que não poderiam trabalhar juntas devido à incompatibilidade de suas interfaces [Gamma et al., 1994]. Esta aplicação é geralmente utilizada em situações onde um sistema ou parte dele é utilizado em outro sistema. Observa-se, desta forma, que este padrão de projetos pode ser bem aplicado quando seja necessário utilizar uma classe já existente, e a interface desenvolvida não é compatível com a referida classe. Outra forma de se aplicar este padrão pode ser observada quando seja preciso criar uma classe reutilizável, que se relaciona com classes distintas, sendo que estas classes não possuem necessariamente interfaces compatíveis, sendo necessário adaptar estas interfaces Exemplo utilizado para este padrão Para demonstrar a utilização deste padrão, é utilizado um exemplo retirado de [Freeman et al., 2004], no qual são implementadas interfaces referentes a dois animais distintos: Patos (Duck) e Perus (Turkey). Estas interfaces possuem, cada uma, dois métodos. Para os patos,

83 Padrão Adapter 63 os métodos são: quack() (referente ao som do pato) e fly() (vôo do pato). Já no caso dos perus, temos os métodos gobble() (som do objeto peru) e fly() (semelhante ao método de vôo do objeto pato). Percebe-se que as interfaces não são compatíveis. O objetivo aqui é fazer com que um objeto do tipo pato possa ser manipulado por meio de uma interface da classe peru, e vice-versa. Se formos simplesmente tentar utilizar uma interface de pato para um objeto peru, haverá incompatibilidade de métodos, retornando erro na saída. A solução utilizada é a de criar duas classes do tipo Adapter. Uma das classes será responsável por adaptar a interface da classe pato (Duck) com os objetos criados da classe peru (Turkey). Essa classe possui o nome TurkeyAdapter pois adapta o objeto da classe Turkey com a interface da classe Duck. Consequentemente, a classe que adapta os objetos da classe Duck com a interface da classe Turkey possui o nome DuckAdapter. A figura 4.1 mostra um diagrama de classes para melhor entendimento deste cenário. Figura 4.1: Diagrama de classes do exemplo para o padrão Adapter. Além das interfaces Duck e Turkey, são definidas duas classes, uma relacionada com os patos, no caso MallardDuck, e outra relacionada com os perus, WildTurkey. As duas

84 Padrão Adapter 64 classes que funcionam como adaptadores, são DuckAdapter e TurkeyAdapter, conforme explicado anteriormente. Para complementar este exemplo, são criadas duas classes com o método principal (main()), sendo elas DuckTestDrive e TurkeyTestDrive. Ambas testam os adaptadores, verificando se obtiveram os resultados esperados Comparação das implementações em Java e ooerlang Em Java e ooerlang todas as classes e interfaces implementadas são similares. interfaces Duck e Turkey são também similares, sendo que o diferencial entre elas é, principalmente, o método relacionado ao som do animal. Entretanto ambas possuem implementações semelhantes. Os códigos mostrados em e mostram as implementações em Java e ooerlang, respectivamente, destas interfaces. 1 public interface Duck { 2 public void quack(); 3 4 } public void fly(); As Código 4.2.1: Interface Duck em Java 1 -interface(duck). 2 -export([quack/0, fly/0]). 3 4 methods. 5 6 quack(). 7 fly(). Código 4.2.2: Interface Duck em ooerlang A diferença entre a interface Duck e a interface Turkey é que, em Turkey, ao invés de existir o método quack(), existe o método gobble(). Esta é a incompatibilidade destas interfaces. A classe TurkeyAdapter implementa o adaptador que permite utilizar a interface Duck para uma instância qualquer da classe WildTurkey, de acordo com o objetivo principal do padrão Adapter. Os códigos mostrados em e mostram a implementação do adaptador TurkeyAdapter em Java e ooerlang, nesta ordem.

85 Padrão Adapter 65 1 public class TurkeyAdapter implements Duck { 2 Turkey turkey; 3 4 public TurkeyAdapter(Turkey turkey) { 5 this.turkey = turkey; 6 } 7 8 public void quack() { 9 turkey.gobble(); 10 } public void fly() { for(int i=0; i < 5; i++) { turkey.fly(); 15 } 16 } 17 } 1 -class(turkeyadapter). 2 -implements(duck). 3 -export([new/1, quack/0, fly/0]). 4 -constructor([new/1]). 5 6 attributes. 7 8 Turkey methods new(turkey) -> 13 self::turkey = Turkey quack() -> 16 Temp = self::turkey, 17 Temp::gobble() fly() -> 20 Temp = self::turkey, 21 Temp::fly(), 22 Temp::fly(), 23 Temp::fly(), Temp::fly(), Temp::fly(). Código 4.2.3: Classe TurkeyAdapter em Java Código 4.2.4: Classe TurkeyAdapter em ooerlang Conforme pode ser observado, houveram adaptações para os dois métodos da classe WildTurkey, gobble() e fly(). Desta forma, o usuário ao fazer uso do adaptador TurkeyAdapter, poderá chamar os métodos da interface Duck para um objeto da classe WildTurkey,

86 Padrão Adapter 66 e observar que os resultados demonstram uma adaptação entre uma interface que inicialmente era incompatível, mas que agora já pode ser utilizada para outro tipo de objeto, no caso, WildTurkey. As classes DuckTestDrive e TurkeyTestDrive tem como objetivo verificar o funcionamento dos adaptadores de interface para um objeto da classe WildTurkey utilizar a interface TurkeyAdapter e para um objeto da classe MallardDuck utilizar a interface DuckAdapter. Dessa forma, cada uma das classes acima citadas instancia um adaptador que deseja testar para ser possivel verificar os resultados obtidos. Os códigos e mostram a implementação da classe TurkeyTestDrive em Java e ooerlang respectivamente. 1 public class TurkeyTestDrive { 2 public static void main(string[] args) { 3 MallardDuck duck = new MallardDuck(); 4 Turkey duckadapter = new DuckAdapter(duck); 5 6 for(int i=0;i<10;i++) { 7 8 System.out.println("The DuckAdapter says..."); duckadapter.gobble(); 9 duckadapter.fly(); 10 } 11 } 12 } Código 4.2.5: Classe principal TurkeyTestDrive em Java 1 -class(turkeytestdrive). 2 -export([main/0]). 3 4 class_methods. 5 6 main() -> 7 Duck = mallardduck::new_(), 8 DuckAdapter = duckadapter::new(duck), 9 10 io:format("the DuckAdapter says..."), 11 DuckAdapter::gobble(), 12 DuckAdapter::fly(), 13 io:format("the DuckAdapter says..."), 14 DuckAdapter::gobble(), DuckAdapter::fly(), io:format("the DuckAdapter says..."), 17 DuckAdapter::gobble(), 18 DuckAdapter::fly(). Código 4.2.6: Classe principal TurkeyTestDrive em ooerlang

87 Padrão Adapter 67 Desta forma, na implementação mostrada, inicialmente é instanciado um objeto do tipo pato, pertencente à classe MallardDuck. Em seguida este objeto é utilizado para que se possa instanciar uma classe que irá funcionar como adaptador, DuckAdapter, para verificar se o objeto originalmente do tipo pato pode ser utilizado com métodos da interface para o objeto peru. Dessa forma utilizam-se os dois métodos da interface Turkey, comprovando a compatibilidade gerada. As figuras 4.2 e 4.3 mostram o resultado da execução deste exemplo em Java e ooerlang, respectivamente. Figura 4.2: Execução do exemplo para o padrão Adapter em Java. Este padrão é comumente utilizado em muitos casos reais, devido à facilidade e necessidade de aplicação do mesmo em diferentes situações. A implementação em ooerlang mostrou-se semelhante à utilizada em Java, e seus resultados demonstraram comportamento similar para ambas as linguagens de programação. Este resultado demonstra a flexibilidade na programação utilizando a extensão ooerlang.

88 Padrão Bridge 68 Figura 4.3: Execução do exemplo para o padrão Adapter em ooerlang. Algumas considerações devem ser feitas na utilização do padrão de projetos Adapter. Por exemplo, o nível de adaptação que deve ser implementado, em relação à classe adaptada a sua relativa interface. Isto varia muito, havendo casos em que a adaptação deve ser total e, em outros casos, apenas parcial. Esta decisão tem relação estreita com o tipo de interface para a qual se irá implementar o adaptador. Caso esta interface não possua todos os métodos presentes na aplicação, é bem provável que haja uma adaptação parcial na implementação. 4.3 Padrão Bridge De acordo com sua definição, o padrão Bridge tem por finalidade: Desacoplar uma abstração de sua implementação para que os dois possam variar independentemente [Gamma et al., 1994]. Em situações nas quais podem existir vários tipos diferentes de abstrações, assim como diversas implementações, a adoção e aplicação deste padrão facilita a manutenção do código-fonte, assim como a extensão, pois facilita o acréscimo de novas abstrações, sem impactar o projeto como um todo.

89 Padrão Bridge 69 Quando se necessite, por exemplo, selecionar ou modificar uma implementação em tempo de execução, deve ser necessário evitar uma ligação forte entre esta implementação e sua referente abstração. Neste caso a utilização do padrão Bridge torna-se necessária. Também pode ser verificado que, ao separar uma abstração de sua implementação, qualquer mudança que se faça na implementação não irá afetar sua respectiva abstração, facilitando assim a manutenção do fonte Exemplo utilizado para este padrão Para exemplificar a utilização do padrão de projetos Bridge, é utilizado um exemplo retirado de [Kulandai, 2012], no qual é modelada uma fábrica que produz dois tipos principais de meios de transportes: carros e bicicletas. Além destes dois produtos, existem duas formas com as quais é possível fabricá-los: produzindo por meio de maquinário fabril e montando de forma manual. Ou seja, existem dois tipos diferentes de produtos e cada produto possui duas formas diferentes de fabricação. A classe que representa o produto carro possui o nome Car, e a classe que representa o produto bicicleta está designada como Bike. A fabricação por meio de processos automatizados da fábrica possui uma classe com o nome Produce, e a fabricação manual tem sua classe, chamada Assemble. Além destas classes, o cenário possui uma classe geral dos veículos, chamada Vehicle, que é herdada por ambos os produtos fabricados. A figura 4.4 mostra um diagrama de classes para melhor entendimento do cenário. As classes sobrepostas possuem implementação similar às classes que as sobrepõem. Como pode ser observado, o padrão Bridge já está sendo utilizado. De acordo com este padrão, o objetivo principal é o de separar uma abstração de sua implementação. Neste caso específico, as abstrações são os tipos de produtos e as implementações são as formas com as quais cada um desses produtos são fabricados. Existe um desacoplamento entre os produtos e seus tipos de fabricação. Caso este padrão não estivesse sendo utilizado, uma solução que poderia vir a ser usada seria a de criar a classe Vehicle sendo herdada pelos dois tipos de veículos. Em seguida, cada veículo estaria associado com ambos os métodos de fabricação. Desta forma haveria duplicação de códigos, pois para cada veículo haveriam duas classes Produce e duas classes

90 Padrão Bridge 70 Figura 4.4: Diagrama de classes do exemplo para o padrão Bridge. Assemble. As classes estariam fortemente acopladas e se fosse necessário incluir um novo tipo de produto, haveria grande impacto e retrabalho no projeto. Porém, neste caso, foi implementado um desacoplamento entre os tipos de veículos e suas formas de fabricação. Por meio da interface Workshop, referente às formas de fabricação, a duplicação de códigos foi evitada e se for necessário inserir novos veículos ou novas formas de fabricação, isto não acarretará grandes problemas ao projeto como um todo Comparação das implementações em Java e ooerlang As classes mostradas no diagrama referente à figura 4.4 foram todas implementadas em ooerlang, tendo-se em vista que a implementação em Java foi retirada de [Kulandai, 2012]. Observadas e ressalvadas as relativas peculiaridades na sintaxe de cada uma das linguagens, as implementações em ooerlang apresentam-se semelhantes às mostradas em Java. Os códigos observados em e revelam a implementação da classe Bike em Java e ooerlang, respectivamente. As implementações da classe Bike seguem a mesma linha de raciocínio em relação às

91 Padrão Bridge 71 1 public class Bike extends Vehicle { 2 3 public Bike(Workshop workshop1, Workshop workshop2) { 4 super(workshop1, workshop2); 5 } 6 7 public void manufacture() { 8 System.out.print("Bike "); 9 workshop1.work(); 10 workshop2.work(); 11 } } 1 -class(bike). 2 -extends(vehicle). 3 -export([new/2, manufacture/0]). 4 -constructor([new/2]). 5 6 methods. 7 Código 4.3.1: Classe Bike em Java 8 9 new(workshop1, WorkShop2) -> self::workshop1 = WorkShop1, 10 self::workshop2 = WorkShop manufacture() -> 13 io:format("bike "), 14 Work1 = self::workshop1, 15 Work2 = self::workshop2, 16 Work1::work(), 17 Work2::work(). Código 4.3.2: Classe Bike em ooerlang implementações da classe Car, por isso apenas o fonte da classe Bike é mostrado. Deve-se observar que cada objeto da classe Bike recebe como parâmetro duas formas de fabricação, referente às duas maneiras com que pode ser produzido. Assim como a classe Car, a classe Bike herda os atributos e métodos da classe Vehicle. Analisando os códigos da classe Assemble, mostrados em e (Java e ooerlang respectivamente), pode-se notar que esta classe implementa o método work(), presente na interface Workshop. Isto ocorre de forma semelhante com o fonte da classe Produce. A utilização da interface Workshop é o ponto fundamental de aplicação do padrão Bridge neste exemplo, possibilitando separar os objetos de suas relativas formas de fabricação.

92 Padrão Bridge 72 1 public class Assemble implements Workshop { 2 3 public void work() { 4 System.out.println(" Assembled."); 5 } 6 } 1 -class(assemble). 2 -implements(workshop). 3 -export([work/0]). 4 5 methods. 6 Código 4.3.3: Classe Assemble em Java 7 work() -> 8 io:format(" Assembled. ~n"). Código 4.3.4: Classe Assemble em ooerlang A classe Vehicle possui dois atributos, relacionados com os dois tipos de fabricação dos veículos da fábrica utilizada no exemplo. Os métodos desta classe são um construtor, que apenas instancia um objeto, dependendo da classe principal (BridgePattern) e o método abstrato manufacture(), que é implementado nas classes Bike e Car. Em relação à classe principal, BridgePattern, para testar a utilização do padrão Bridge, são instanciados dois objetos, um do tipo Car e outro do tipo Bike. Para cada um destes, é passado como parâmetro de construção os dois distintos modos de fabricação de um veículo. Em seguida é utilizado o método manufacture(), que é implementado em cada um dos veículos, e realiza a fabricação do veículo das duas formas existentes. A implementação desta classe está mostrada nos códigos em e public class BridgePattern { 2 3 public static void main(string[] args) { 4 5 Vehicle vehicle1 = new Car(new Produce(), new Assemble()); 6 vehicle1.manufacture(); 7 Vehicle vehicle2 = new Bike(new Produce(), new Assemble()); 8 vehicle2.manufacture(); 9 } 10 } Código 4.3.5: Classe principal BridgePattern em Java

93 Padrão Bridge class(bridgepattern). 2 -export([main/0]). 3 4 class_methods. 5 6 main() -> 7 Vehicle1 = car::new(produce::new_(), assemble::new_()), 8 Vehicle1::manufacture(), 9 10 Vehicle2 = bike::new(produce::new_(), assemble::new_()), 11 Vehicle2::manufacture(). Código 4.3.6: Classe principal BridgePattern em ooerlang Assim para ambos os veículos, os dois métodos de fabricação são testados. Percebe-se assim que, dependendo da necessidade do sistema, poderiam ser incluídos novos veículos e eles já poderiam possuir as duas formas de fabricação que já existem, sem necessidade de alterar nenhum código em qualquer outra classe de veículos. O mesmo é valido em uma situação em que fosse necessário retirar de fabricação algum tipo de veículo. As figuras 4.5 e 4.6 mostram a execução deste exemplo em Java e ooerlang. A extensão do Erlang para orientação à objetos, ooerlang, mostrou poder ser utilizada na implementação de fontes similares aos fontes utilizados no exemplo mostrado para o padrão Bridge. Este padrão estrutural é bem aplicado em situações onde seja necessário variar as implementações distintamente de suas abstrações. Com a aplicação deste padrão de projeto, é possível perceber que a inserção e/ou exclusão de novos veículos na fábrica utilizada neste exemplo, não iria ocasionar um grande impacto no projeto como um todo. Similarmente, se fosse necessário incluir novas formas de fabricação de veículos, ou retirar alguma forma já existente, também não haveriam impactos no projeto inteiro. As principais consequencias provindas da utilização deste padrão de projetos podem ser citadas como sendo o desacoplamento de uma interface com uma implementação (eliminando dependências), melhoramento da extensibilidade do fonte em relação às hierarquias de abstração e implementação (tornam-se independentes), e a característica de encapsulamento deste padrão, que não mostra ao usuário detalhes da implementação que não são do interesse do mesmo.

94 Padrão Composite 74 Figura 4.5: Execução do exemplo para o padrão Bridge em Java. 4.4 Padrão Composite De acordo com sua definição, o padrão de projetos Composite tem por objetivo: Compor objetos em estruturas de árvore para representar hierarquias todo-parte. Composite permite que clientes tratem objetos individuais e composições de objetos de maneira uniforme [Gamma et al., 1994]. Assim, sempre que um cenário tenha como característica principal a necessidade de tratar diferentes estruturas de objetos em hierarquias, tendo acesso a todos os nós da árvore, é possível utilizar o padrão Composite. A necessidade de utilização deste padrão é verificada quando, ao se possuir vários objetos configurados em estruturas semelhantes ou diferentes, seja necessário representar hierarquias todo-parte destes objetos e suas referidas estruturas. Também pode-se dizer que este padrão é aplicável quando o objetivo da modelagem é o de permitir ao usuário do sistema ser capaz de ignorar a diferença entre composições de objetos e objetos individuais,

95 Padrão Composite 75 Figura 4.6: Execução do exemplo para o padrão Bridge em ooerlang. tratando-os uniformemente Exemplo utilizado para este padrão Para tratar do padrão de projetos Composite, é utilizado um exemplo retirado de [Making, 2013], no qual trabalha-se com uma estrutura de hierarquias. É uma estrutura simplificada, cujo objetivo restringe-se apenas a verificar a utilização do referido padrão e a forma com que pode-se aplicar este padrão a diferentes sistemas que possuam o mesmo tipo de problema e que necessitem de uma solução semelhante. Na estrutura utilizada existe uma classe chamada Primitive. Trata-se de um objeto isolado, que não esteja contido em uma composição. Este objeto armazena um valor numérico. Também tem-se uma classe chamada Composite. Esta classe é uma composição de objetos da classe Primitive. A classe Composite é herdada por outras duas classes, Row (linha) e Column (coluna). Cada linha é uma composição de valores Primitive, e o mesmo é válido para as colunas (Column). As classes Row e Column são tipos diferentes de composições. Podem armazenar diversos valores, sejam eles de outras composições (Composite) ou valores isolados (Primitive).

96 Padrão Composite 76 Eis a característica do padrão Composite neste exemplo: é possível criar uma estrutura do tipo todo-parte, e deve-se implementar uma forma de se trabalhar com todas as hierarquias de classes de maneira uniforme. Ambas as classes Composite e Primitive implementam a interface Component. Isto significa dizer que será criada uma estrutura com linhas e colunas e que, tanto as composições de objetos quanto os objetos isolados são componentes pertencentes a essa mesma estrutura. A figura 4.7 mostra com mais detalhes um diagrama de classes referente a este exemplo para melhor entendimento do problema. Figura 4.7: Diagrama de classes do exemplo para o padrão Composite. A classe Composite possui um atributo chamado children, que é uma lista na qual é possivel armazenar outros objetos de composição, sejam linhas ou colunas, assim como também é possivel armazenar valores isolados. Considerando que podem-se armazenar várias composições de objetos dentro de uma composição e em cada uma destas composições também armazena outras composições, percebe-se como uma simples estrutura pode tornar-se bastante complexa com diversas inserções ao longo do tempo.

97 Padrão Composite Comparação das implementações em Java e ooerlang Todas as classes mostradas na figura 4.7 são implementadas em Java e ooerlang. Analisando inicialmente a classe Composite, verifica-se, de acordo com o código mostrado em (implementação em Java desta classe), que esta classe possui como atributo um valor e uma lista em que podem ser armazenados outros valores. Além do construtor, existe um método responsável por inserir elementos na lista filhos e um método chamado transverse(). 1 public class Composite implements Component{ 2 private Component[] children = new Component[9]; 3 private int total; 4 private int value; 5 6 public Composite(int val) { 7 value = val; 8 total = 0; 9 } public void add(component c) { 12 children[total++] = c; 13 } public void transverse() { 16 System.out.print( value + " " ); for (int i=0; i < total; i++) children[i].transverse(); 19 } 20 } Código 4.4.1: Classe Composite em Java O método transverse() é o responsável por fazer a varredura na estrutura, conforme a definição do padrão. Este método imprime o valor da estrutura atual e é chamado recursivamente para todos os elementos filhos da estrutura atual. Desta forma, todos os elementos (sejam composições de objetos ou objetos isolados) que tiverem uma hierarquia menor que a atual serão visitados. O código em mostra a implementação desta mesma classe em ooerlang. A classe Primitive é semelhante à classe Composite, porém a mesma não possui uma lista para elementos filhos da estrutura. Ambas herdam os métodos da classe Component. Além disso, a classe Composite, conforme dito anteriormente, é herdada por duas classes que representam tipos diferentes de composição: Row e Column (linha e coluna). Suas im-

98 Padrão Composite class(composite). 2 -implements(component). 3 -export([new/1, add/1, transverse/0]). 4 -constructor([new/1]). 5 6 attributes. 7 8 Children; 9 Total; 10 Value methods new(val) -> 15 self::children = [], 16 self::value = Val, 17 self::total = add(c) -> 20 self::children = self::children ++ [C], 21 self::total = self::total transverse() -> 24 io:format("~p ", [self::value]), 25 transverse_aux(self::children) transverse_aux([]) -> ok; 28 transverse_aux([child Children]) -> 29 Child::transverse(), 30 transverse_aux(children). Código 4.4.2: Classe Composite em ooerlang plementações são bastante semelhantes. Os códigos mostrados em e apresentam as implementações da classe Row em Java e ooerlang respectivamente. 1 public class Row extends Composite{ 2 3 public Row(int val) { 4 super( val ); 5 } public void transverse() { System.out.print( "Row" ); 9 super.transverse(); 10 } 11 } Código 4.4.3: Classe Row em Java Observa-se que esta classe possui um construtor e o método transverse(), responsável

99 Padrão Composite class(row). 2 -extends(composite). 3 -export([new/1, transverse/0]). 4 -constructor([new/1]). 5 6 methods. 7 8 new(val) -> 9 self::children = [], 10 self::value = Val, 11 self::total = transverse() -> io:format("row"), 15 super::transverse(). Código 4.4.4: Classe Row em ooerlang por realizar a visitação em todos os elementos de hierarquia inferior ao atual. Ambos os métodos funcionam exatamente da mesma forma com a qual funcionam os mesmos métodos na superclasse Composite. Este comportamento é o mesmo encontrado na classe Column, que também herda os métodos da classe Composite. A classe principal, chamada CompositeDemo é a responsável por testar a criação da estrutura e verificação dos resultados na varredura da estrutura criada. Em sua implementação são instanciados três objetos do tipo linha (Row) e dois objetos do tipo coluna (Column). Em seguida estas composições são inseridas umas dentro das outras, assim como nesta estrutura também são inseridos valores isolados. Os códigos e mostram a implementação desta classe em Java e ooerlang. Tanto em Java quanto em ooerlang é criada a mesma estrutura, para facilitar a comparação da execução dos distintos fontes gerados. Após a criação das 3 linhas e das 2 colunas, as colunas 2 e 3 são inseridas na linha 1. Em seguida as linhas 4 e 5 são inseridas na linha 3. Depois destes passos são inseridos valores isolados na estrutura, em todos os objetos do tipo Composite criados. Desta forma logrou-se montar a estrutura de testes. Após toda a estrutura ter sido construída, é utilizado o método transverse(). O objeto que utilizou-se deste método é o mesmo que na estrutura formada está presente na maior hierarquia, no caso a primeira linha instanciada (Row). Desta forma garante-se que toda a estrutura será percorrida, uma vez que se sabe que o método transverse() funciona recursivamente para composições da estrutura de nível inferior. As figuras 4.8 e 4.9 mostram

100 Padrão Composite 80 1 public class CompositeDemo { 2 3 public static void main(string[] args) { 4 Composite first = new Row( 1 ); // Row1 5 Composite second = new Column( 2 ); // 6 Composite third = new Column( 3 ); // +-- Col2 7 Composite fourth = new Row( 4 ); // 8 Composite fifth = new Row( 5 ); // first.add( second ); // +-- Col3 10 first.add( third ); // 11 third.add( fourth ); // +-- Row4 12 third.add( fifth ); // 13 first.add( new Primitive( 6 ) ); // second.add( new Primitive( 7 ) ); // +-- Row5 15 third.add( new Primitive( 8 ) ); // 16 fourth.add( new Primitive( 9 ) ); // fifth.add( new Primitive(10 ) ); // first.transverse(); // } 20 } 1 -class(compositedemo). 2 -export([main/0]). 3 4 class_methods. 5 Código 4.4.5: Classe principal CompositeDemo em Java 6 main() -> 7 First = row::new(1), %% Row1 8 Second = column::new(2), %% 9 Third = column::new(3), %% +-- Col2 10 Fourth = row::new(4), %% Fifth = row::new(5), %% %% Col3 13 First::add(Second), %% 14 First::add(Third), %% +-- Row4 15 Third::add(Fourth), %% 16 Third::add(Fifth), %% First::add(primitive::new(6)), %% +-- Row5 18 Second::add(primitive::new(7)), %% 19 Third::add(primitive::new(8)), %% Fourth::add(primitive::new(9)), %% Fifth::add(primitive::new(10)), %% First::transverse(). Código 4.4.6: Classe principal CompositeDemo em ooerlang a execução deste exemplo em Java e ooerlang, respectivamente. Para melhor entendimento espacial da estrutura, nos fontes mostrados em e 4.4.6,

101 Padrão Composite 81 Figura 4.8: Execução do exemplo para o padrão Composite em Java. que representam as implementações em Java e ooerlang da classe CompositeDemo, inseriuse um comentário mostrando a estrutura gerada no final de toda a execução, sendo então percorrida por inteiro, conforme é verificado nas figuras 4.8 e 4.9. O padrão estrutural Composite mostra-se muito bem aplicado em situações de estruturas e composições de estruturas. Quando seja necessário trabalhar com diferentes estruturas de forma igual, a utilização deste padrão é necessária. Em ooerlang, assim como em Java, foi utilizada a recursão para que fosse possível percorrer toda a estrutura formada. A recursão é uma solução prática e viável para este tipo de problema. Na utilização do padrão de projetos Composite, verifica-se a utilização de hierarquias de classes formada por objetos primitivos e objetos compostos. Percebe-se também que o usuário passa a tratar de maneira mais simples as composições e os objetos primitivos, uma vez que todos são tratados uniformemente. A inserção de novos tipos de componentes

102 Padrão Decorator 82 Figura 4.9: Execução do exemplo para o padrão Composite em ooerlang. também é facilitada pela utilização deste padrão, evitando a necessidade de modificar o código-fonte de todo o projeto. 4.5 Padrão Decorator Este padrão de projeto, segundo sua formal definição, tem por objetivo: Anexar responsabilidades adicionais a um objeto dinamicamente. Decorators oferecem uma alternativa flexível ao uso de herança para estender uma funcionalidade [Gamma et al., 1994]. Em certas situações, é mais conveniente incluir novas responsabilidades a um objeto sem que seja necessário modificar código fonte de suas subclasses, melhorando a utilização do referido objeto pelo usuário. Existe a possibilidade de se utilizar do padrão Decorator para uma melhor modelagem do sistema nos casos em que haja a necessidade de adicionar responsabilidades a objetos individuais de forma dinâmica e transparente, ou seja, sem que isto afete outros objetos. Outra situação em que este padrão pode ser utilizado é quando estender uma classe por subclasses mostre ser uma solução inadequada. Em alguns casos isto pode gerar excesso

103 Padrão Decorator 83 de subclasses e consequente dificuldade na manutenção do sistema Exemplo utilizado para este padrão Para utilizar este padrão de projeto, foi utilizado um exemplo retirado de [Freeman et al., 2004], no qual é implementado um sistema gerenciador de uma loja de cafés. Na referida loja, é possível escolher diferentes sabores de cafés, assim como é possível, dependendo do cliente, colocar condimentos a mais no café escolhido. O sistema gerencia principalmente os pedidos dos clientes, verificando em seguida quanto foi o valor da compra. Existem quatro (4) sabores principais de café neste modelo: DarkRoast, Decaf, Expresso e HouseBlend. Cada sabor de café torna-se uma classe. Existem também quatro (4) tipos diferentes de condimentos, são eles: Milk, Mocha, Soy e Whip. Para cada pedido, o cliente escolhe o sabor do café e, se desejar, também adiciona quantos condimentos quiser. Ao final o valor do pedido é retornado ao cliente. A figura 4.10 mostra um diagrama de classes deste exemplo para melhor entendimento do exemplo. As classes sobrepostas possuem implementação similar às classes que as sobrepõem. Se a modelagem deste sistema tivesse escolhido resolver o problema criando várias subclasses, haveria a necessidade de criar inúmeras delas, uma vez que existem diversas combinações de diferentes sabores de cafés com diferentes tipos e quantidades de condimentos. Deve ser considerado o fato de que cada café possui um valor próprio e que cada condimento também possui um valor próprio, desta forma, os tipos de condimentos em um pedido de café incrementam o preço final do mesmo. Para evitar que existam inúmeras classes diferentes de café, é utilizado o padrão Decorator. Inicialmente, quando um pedido de café é feito, é instanciado um objeto referente ao sabor do café. Em seguida, sempre que um condimento for solicitado para ser incluído no café, é instanciado um objeto da classe referente ao condimento e este objeto realiza a decoração do objeto sabor, aumentando a descrição do pedido e seu referido valor. Desta forma é possivel pedir diversos tipos diferentes de sabores com diversos condimentos e combinações diferentes de condimentos. Cada inclusão de um novo condimento faz com que o objeto referente ao sabor do café seja incrementado. Este é o principal

104 Padrão Decorator 84 Figura 4.10: Diagrama de classes do exemplo para o padrão Decorator. aspecto do padrão Decorator. O pedido vai sendo incrementado em tempo de execução. Isto reduz em grande escala a quantidade de classes utilizada, torna a solução mais viável e permite, inclusive, que sejam feitas diversas inclusões do mesmo condimento em um único pedido de café Comparação das implementações em Java e ooerlang Em ambas as implementações (Java e ooerlang), todos os tipos de sabores diferentes de café estendem a classe Beverage, que é a classe geral dos tipos de bebidas. Cada tipo de bebida implementa o método cost(), pois cada bebida possui seu próprio sabor. Cada diferente tipo de bebida possui uma diferente descrição, que é definida no momento da instanciação de um objeto de alguma das classes de bebidas. Os códigos e mostram a implementação da classe Espresso em Java e ooerlang Na instanciação do objeto Espresso, o atributo description apenas recebe um novo valor, de acordo com o sabor da bebida, neste caso o café do tipo expresso. Para cada tipo de

105 Padrão Decorator 85 1 public class Espresso extends Beverage { 2 3 public Espresso() { 4 description = "Espresso"; 5 } 6 7 public double cost() { 8 return 1.99; 9 } 10 } class(expresso). 2 -extends(beverage). 3 -export([new/0, cost/0]). 4 -constructor([new/0]). 5 6 methods. 7 Código 4.5.1: Classe Espresso em Java 8 new() -> 9 self::description = "Expresso" cost() -> Código 4.5.2: Classe Expresso em ooerlang bebida, a implementação é semelhante, sendo que as principais diferenças são as descrições das bebidas e o valor de cada uma. Em relação aos condimentos, cada condimento também possui implementações semelhantes. Todas as classes que pertencem ao tipo condimento implementam a classe CondimentDecorator, que possui a descrição total de cada pedido a ser feito. Além disso cada classe referente a um tipo de condimento recebe como parâmetro um objeto do tipo bebida, e aumenta sua descrição e seu preço. Desta forma um objeto está sendo modificado em tempo de execução. Os códigos e mostram a implementação da classe Soy em Java e ooerlang. Conforme pode ser observado, a classe Soy (referente ao condimento soja) já possui um atributo do tipo Beverage que pode receber qualquer instância de uma classe pertencente aos diferentes sabores de cafés. Nesta classe, tanto o método que trata da manipulação da descrição da bebida quanto o método que retorna o valor da bebida, incrementam o que existia na bebida recebida durante a instanciação da classe de condimentos. Trabalhando

106 Padrão Decorator 86 1 public class Soy extends CondimentDecorator { 2 Beverage beverage; 3 4 public Soy(Beverage beverage) { 5 this.beverage = beverage; 6 } 7 8 public String getdescription() { 9 return beverage.getdescription() + ", Soy"; 10 } public double cost() { 13 return.15 + beverage.cost(); 14 } 15 } Código 4.5.3: Classe Soy em Java 1 -class(soy). 2 -extends(condimentdecorator). 3 -export([new/1, get_description/0, add_cost/0]). 4 -constructor([new/1]). 5 6 attributes. 7 8 Beverage methods new(beverage) -> 13 self::beverage = Beverage get_description() -> Temp = self::beverage, Temp::get_description() ++ ", Soy" add_cost() -> 20 Temp = self::beverage, Temp::cost(). Código 4.5.4: Classe Soy em ooerlang com esta implementação, a cada novo incremento de condimento, existe incremento na descrição e no valor da bebida. Portanto, com a utilização desta forma de modelagem é possivel incluir inúmeros tipos de condimentos a uma única bebida, com ou sem repetição. No final, todos os preços dos condimentos reunidos são somados juntamente com o preço da bebida pura. A classe principal deste exemplo, StarbuzzCoffee possui esta denominação pois refere-se ao nome

107 Padrão Decorator 87 fictício desta loja de cafés. Na implementação da classe principal StarbuzzCoffee, são feitas instanciações de três (3) tipos diferentes de bebidas. No primeiro caso, não foi incluído nenhum condimento na bebida escolhida. No segundo caso foram incluídos condimentos diferentes na bebida, verificando seu preço final. E no terceiro caso, além de serem incluídos condimentos, um dos condimentos foi incluído duas vezes. Os códigos mostrados em e mostram a implementação desta classe em Java e ooerlang. 1 public class StarbuzzCoffee { 2 3 public static void main(string args[]) { 4 Beverage beverage = new Espresso(); 5 System.out.println(beverage.getDescription() 6 + " $" + beverage.cost()); 7 8 Beverage beverage2 = new DarkRoast(); 9 beverage2 = new Mocha(beverage2); 10 beverage2 = new Mocha(beverage2); 11 beverage2 = new Whip(beverage2); 12 System.out.println(beverage2.getDescription() 13 + " $" + beverage2.cost()); Beverage beverage3 = new HouseBlend(); 16 beverage3 = new Soy(beverage3); 17 beverage3 = new Mocha(beverage3); 18 beverage3 = new Whip(beverage3); 19 System.out.println(beverage3.getDescription() 20 + " $" + beverage3.cost()); } } Código 4.5.5: Classe principal StarbuzzCoffee em Java Percebe-se que, no código da classe principal, em relação aos pedidos da segunda e terceira bebida, sempre que um novo condimento vai ser incluído no pedido, ocorre a instanciação do objeto referente ao condimento, sendo que nesta instanciação, a própria bebida que irá receber o condimento é passada como parâmetro de instanciação do condimento. É desta forma que o objeto vai sendo decorado em tempo de execução. No código para cada inclusão de um novo condimento, um novo objeto é criado, sendo que este novo objeto recebe todas as modificações realizadas anteriormente. Esta implementação foi feita desta forma devido à característica própria do Erlang, que não permite a uma variável a mudança de seu valor em tempo de execução. Portanto, a idéia

108 Padrão Decorator class(starbuzzcoffee). 2 -export([main/0]). 3 4 class_methods. 5 6 main() -> 7 Beverage = expresso::new(), 8 io:format("~p $ ~p~n", [Beverage::get_description(), Beverage::cost()]), 9 10 BevTemp1 = darkroast::new(), 11 BevTemp2 = mocha::new(bevtemp1), 12 BevTemp3 = mocha::new(bevtemp2), BevTemp4 = whip::new(bevtemp3), io:format("~p $ ~p~n", [BevTemp4::get_description(), BevTemp4::cost()]), BevTemp5 = houseblend::new(), 17 BevTemp6 = soy::new(bevtemp5), 18 BevTemp7 = mocha::new(bevtemp6), 19 BevTemp8 = whip::new(bevtemp7), io:format("~p $ ~p~n", [BevTemp8::get_description(), BevTemp8::cost()]). Código 4.5.6: Classe principal StarbuzzCoffee em ooerlang central do padrão Decorator ainda persiste nesta implementação. As figuras 4.11 e 4.12 mostram a execução deste exemplo em Java e ooerlang, respectivamente. Na implementação do exemplo da loja de cafés, que trata do padrão de projetos Decorator, é possivel perceber que a extensão ooerlang mostra-se apta a realizar uma modelagem com os mesmos conceitos presentes na implementação da linguagem Java. Os resultados são comprovados na verificação do resultado da execução deste exemplo nas duas linguagens, mostrando saídas semelhantes. Desta forma pode-se afirmar que os fontes compilados são equivalentes. A implementação em ooerlang apresenta-se bastante semelhante à realizada em Java. A única diferença observada na codificação deste exemplo ocorre na inclusão de condimentos às bebidas que estavam sendo pedidas. Enquanto que em Java é utilizado o mesmo objeto para receber um novo condimento, em ooerlang, torna-se necessário criar um novo objeto para cada inclusão de um novo condimento. Mas este detalhe não modifica o resultado final, continuando a implementar a idéia central do padrão Decorator: modificar um objeto, atribuíndo-lhe novas responsabilidades em tempo de execução. Na utilização do padrão de projetos Decorator, percebe-se, de um modo geral, que o sistema a utilizá-lo ganha mais flexibilidade do que utilizando heranças estáticas (no exemplo

109 Padrão Facade 89 Figura 4.11: Execução do exemplo para o padrão Decorator em Java. StarbuzzCoffee, a utilização de herança para os condimentos seria uma solução impraticável). Também observa-se que um objeto decorado é diferente do objeto originalmente instanciado. Um sistema que se utilize deste padrão de projetos irá ocasionalmente passar a possuir pequenos objetos decoradores, como consequência. No caso da loja Starbuzz- Coffee, esses objetos são os condimentos. 4.6 Padrão Facade Conforme o próprio nome sugere, este padrão tem por finalidade principal a de: Oferecer uma interface única para um conjunto de interfaces de um subsistema. Facade define uma interface de nível mais elevado que torna o subsistema mais fácil de usar [Gamma et al., 1994]. Este padrão possui grande possibilidade de aplicação nas situações em que

110 Padrão Facade 90 Figura 4.12: Execução do exemplo para o padrão Decorator em ooerlang. um sistema possui diversas interfaces que realizam diferentes tarefas. Desta forma este padrão é bastante utilizado para facilitar o usuário, que realiza suas tarefas de uma forma mais fácil ao utilizar-se de apenas uma interface simples, que abstrai o trabalho de interagir com diferentes interfaces. Assim é possivel prover uma simples interface para um subsistema complexo. Outra vantagem na aplicação do padrão Facade é na necessidade de portabilidade de sistemas, pois a utilização deste padrão diminui as dependências entre clientes e as implementações de classes abstratas Exemplo utilizado para este padrão Para este padrão foi modelado um sistema retirado de [Freeman et al., 2004] que controla as operações a serem utilizadas em um Home Theater. Verifica-se que esse sistema de áudio e vídeo possui diferentes equipamentos com os quais é possivel operar. Cada equipamento foi modelado como pertendo a uma classe, sendo eles: Amplifier (amplificador), CdPlayer (reprodutor de CD), DvdPlayer (reprodutor de DVD), Tuner (sintonizador de rádio), PopcornPopper (máquina de pipocas), Projector (projetor), Screen (tela) e TheaterLights (luzes do ambiente).

111 Padrão Facade 91 Se, por exemplo, esse sistema estivesse modelado com todas as suas interfaces separadas, para um usuário assistir a um filme, várias ações deveriam ser executadas (Ligar a máquina de pipocas, retirar as pipocas, ajustar luzes do ambiente, baixar tela de projeção, ligar projetor, etc.) Todas essas ações seriam necessárias para apenas assistir a um filme. Verifica-se então a necessidade de aplicar um padrão de projetos que facilite a utilização do usuário para com o projeto como um todo, fazendo com que uma interface simples possa facilitar a manipulação do sistema e de suas funcionalidades. Este cenário refere-se ao padrão Facade, que utiliza-se de uma interface (conhecida como fachada ) com o objetivo de simplificar a realização de ações que o sistema possa realizar. A figura 4.13 mostra um diagrama de classes para melhor entendimento do referido exemplo. As classes sobrepostas possuem implementação similar às classes que as sobrepõem. Verifica-se que todas as classes correspondentes a cada equipamento ou controlador está ligada com a classe que funciona como a fachada do sistema, chamada de HomeTheater- Facade. Se, por acaso, um usuário desejar assistir a um filme, ou simplesmente ouvir um CD ou o rádio, na classe HomeTheaterFacade foram definidos métodos que realizam estas ações facilmente, simplificando a quantidade de tarefas que o usuário precisa realizar para se chegar a um objetivo Comparação das implementações em Java e ooerlang Cada classe correspondente a um equipamento pode realizar diferentes ações neste dispositivo. Por exemplo, a classe CdPlayer pode realizar as seguintes ações no aparelho reprodutor de CD: ligar, desligar, ejetar, reproduzir faixa, pausar/parar reprodução etc. E esta quantidade de ações existe em cada um dos equipamentos. Desta forma é fácil verificar a complexidade do sistema sem a utilização do padrão Facade. Para este cenário é explicado o caso particular em que se deseja assistir a um filme. Inicialmente será observada a classe DvdPlayer. Esta classe possui os principais comandos que podem ser realizados no aparelho reprodutor de DVD do sistema utilizado, tais como ligar, desligar, ejetar DVD, reproduzir filme etc. Mas além dessas ações, é necessário perceber que outras classes devem ser trabalhadas para que se realize a ação de assistir a um filme, como, por exemplo, ajustar tela, ligar projetor, entre outras.

112 Padrão Facade 92 Figura 4.13: Diagrama de classes do exemplo para o padrão Facade. Observando inicialmente a classe DvdPlayer, verificando apenas alguns de seus métodos implementados em Java no código e em ooerlang no código mostrado em 4.6.2, observamos que os métodos referentes ao dispositivo reprodutor de DVD foram implementados normalmente, apenas para a utilização em objetos desta classe. Os fontes mostrados são semelhantes em sua idéia principal tanto em Java quanto em ooerlang, observadas as diferenças de sintaxe de ambas as linguagens. Mas para que seja possível assistir a um filme, é preciso que todos os aparelhos a serem utilizados neste

113 Padrão Facade 93 1 public class DvdPlayer { 2 String description; 3 int currenttrack; 4 Amplifier amplifier; 5 String movie; 6 7 public void on() { 8 System.out.println(description + " on"); 9 } public void off() { 12 System.out.println(description + " off"); 13 } public void eject() { 16 movie = null; 17 System.out.println(description + " eject"); 18 } public void play(string movie) { 21 this.movie = movie; 22 currenttrack = 0; } System.out.println(description + " playing \"" + movie + "\""); Código 4.6.1: Classe DvdPlayer em Java processo sejam ligados e configurados. Este é justamente o trabalho realizado na classe HomeTheaterFacade, na qual cada ação específica (reproduzir música, ouvir rádio, ver filme etc) é implementada nesta classe. Os códigos mostrados em e mostram a implementação da classe HomeTheaterFacade em Java e ooerlang. Nas implementações vistas em e verifica-se que apenas o método responsável por gerenciar todas as atividades relativas à ação de ver um filme foi mostrado. Os outros métodos, referentes à outras ações foram abstraídos para melhor entendimento da utilização do padrão Facade. O método implementado nesta classe para que se possa assistir à um filme chama-se watchmovie() que recebe como parâmetro o nome do filme. Verifica-se então que, se não estivesse sendo utilizada uma classe para funcionar como simplificadora de interfaces (Facade), seria necessário chamar métodos referentes às classes PopcornPopper, TheaterLights, Screen, Projector, Amplifier e DvdPlayer. Graças à classe HomeTheaterFacade, todos esses métodos são chamados dentro do método responsável por preparar um filme a ser assistido. Assim, o usuário tem muito menos trabalho para poder realizar uma ação utilizando deste sistema.

114 Padrão Facade class(dvdplayer). 2 -export([new/2, on/0, off/0, eject/0, play/1, stop/0, pause/0]). 3 -export([set_two_channel_audio/0, set_surround_audio/0, to_string/0]). 4 -constructor([new/2]). 5 6 attributes. 7 8 Description; 9 CurrentTrack; 10 Amplifier; 11 Movie methods on() -> 16 io:format("~p on~n", [self::description]) off() -> 19 io:format("~p off~n", [self::description]) eject() -> 22 self::movie = "No title", 23 io:format("~p eject~n", [self::description]) play(movie) -> 26 self::movie = Movie, 27 self::currenttrack = 0, 28 io:format("~p playing ~p~n", [self::description, self::movie]). Código 4.6.2: Classe DvdPlayer em ooerlang A classe principal deste exemplo chama-se HomeTheaterTestDrive. Ao ser executada, esta classe inicialmente instancia objetos para todas as classes referentes aos equipamentos do sistema de áudio e vídeo modeladas. Em seguida é instanciado um objeto referente à classe HomeTheaterFacade, que recebe como parâmetros de entrada todos os objetos anteriormente instanciados. A classe HomeTheaterTestDrive é mostrada nos códigos e 4.6.6, em Java e ooerlang, respectivamente. Após todos os objetos de cada classe que representa um equipamento serem instanciados, e o objeto referente à classe HomeTheaterFacade também ser instanciado, este último objeto pode ser utilizado para realizar as ações complexas destes equipamentos de forma simples e rápida. No caso observado, é utilizado apenas o método para assistir a um filme. Verifica-se que qualquer ação relativa a este sistema pode ser facilmente executada utilizando-se dos métodos implementados na classe HomeTheaterFacade. As figuras mostradas em 4.14 e 4.15 mostram, respectivamente, a execução deste exemplo em Java e

115 Padrão Facade 95 1 public class HomeTheaterFacade { 2 Amplifier amp; 3 Tuner tuner; 4 DvdPlayer dvd; 5 CdPlayer cd; 6 Projector projector; 7 TheaterLights lights; 8 Screen screen; 9 PopcornPopper popper; public void watchmovie(string movie) { 12 System.out.println("Get ready to watch a movie..."); popper.on(); popper.pop(); 15 lights.dim(10); 16 screen.down(); 17 projector.on(); 18 projector.widescreenmode(); 19 amp.on(); 20 amp.setdvd(dvd); 21 amp.setsurroundsound(); 22 amp.setvolume(5); dvd.on(); dvd.play(movie); 25 } Código 4.6.3: Classe HomeTheaterFacade em Java ooerlang. Foi possível observar que o padrão de projetos Facade mostrou-se implementável na extensão orientada a objetos ooerlang. Este padrão visa facilitar a utilização de um sistema que seja complexo, geralmente possuindo diferentes interfaces. No exemplo utilizado, para cada ação a ser realizada era necessário chamar diversos métodos de diferentes classes, dificultando as ações do usuário. Outro detalhe a ser observado é o de que, no exemplo utilizado, ao invés de existirem diversas interfaces, existem diferentes classes, uma para cada tipo de dispositivo. Mas a utilização do padrão Facade é semelhante, tanto na simplificação de classes quanto de interfaces. Observa-se que, nenhuma classe foi modificada para que este padrão pudesse ser utilizado. Apenas utilizou-se uma classe principal que realiza todas as pequenas ações para se concluir cada tarefa peculiar desse exemplo. Uma das facilidades verificadas ao se utilizar do padrão Facade, conforme visto anteriormente, é a de proteger o cliente dos componentes do subsistema, reduzindo notavelmente

116 Padrão Facade class(hometheaterfacade). 2 -export([new/8, watch_movie/1, end_movie/0, listen_to_cd/1, end_cd/0]). 3 -export([listen_to_radio/1, end_radio/0]). 4 -constructor([new/8]). 5 6 attributes. 7 8 Amp; 9 Tuner; 10 Dvd; 11 Cd; 12 Projector; Lights; Screen; 15 Popper methods watch_movie(movie) -> 20 io:format("get ready to watch a movie...~n"), 21 Temp1 = self::popper, 22 Temp1::on(), Temp1::pop(), Temp2 = self::lights, 25 Temp2::dim(10), 26 Temp3 = self::screen, 27 Temp3::down(), 28 Temp4 = self::projector, 29 Temp4::on(), 30 Temp4::widescreen_mode(), 31 Temp5 = self::amp, 32 Temp5::on(), Temp5::set_dvd(self::Dvd), Temp5::set_surround_sound(), 35 Temp5::set_volume(5), 36 Temp6 = self::dvd, 37 Temp6::on(), 38 Temp6::play(Movie). Código 4.6.4: Classe HomeTheaterFacade em ooerlang a quantidade de objetos com os quais o cliente passa a interagir. Dessa forma é promovido um acoplamento frágil entre os subsistemas e seus clientes. Isto significa dizer que os componentes de um subsistema podem ser modificados sem que isto afete diretamente os clientes.

117 Padrão Flyweight 97 1 public class HomeTheaterTestDrive { 2 public static void main(string[] args) { 3 Amplifier amp = new Amplifier("Top-O-Line Amplifier"); 4 Tuner tuner = new Tuner("Top-O-Line AM/FM Tuner", amp); 5 DvdPlayer dvd = new DvdPlayer("Top-O-Line DVD Player", amp); 6 CdPlayer cd = new CdPlayer("Top-O-Line CD Player", amp); 7 Projector projector = new Projector("Top-O-Line Projector", dvd); 8 TheaterLights lights = new TheaterLights("Theater Ceiling Lights"); 9 Screen screen = new Screen("Theater Screen"); 10 PopcornPopper popper = new PopcornPopper("Popcorn Popper"); HomeTheaterFacade hometheater = new HomeTheaterFacade(amp, tuner, dvd, cd, projector, screen, lights, popper); hometheater.watchmovie("raiders of the Lost Ark"); 17 hometheater.endmovie(); 18 } 19 } Código 4.6.5: Classe principal HomeTheaterTestDrive em Java 1 -class(hometheatertestdrive). 2 -export([main/0]). 3 4 class_methods. 5 6 main() -> 7 Amp = amplifier::new("top-o-line Amplifier"), 8 Tuner = tuner::new("top-o-line AM/FM Tuner", Amp), 9 Dvd = dvdplayer::new("top-o-line DVD Player", Amp), 10 Cd = cdplayer::new("top-o-line CD Player", Amp), 11 Projector = projector::new("top-o-line Projector", Dvd), 12 Lights = theaterlights::new("theater Ceiling Lights"), 13 Screen = screen::new("theater Screen"), 14 Popper = popcornpopper::new("popcorn Popper"), HomeTheater = hometheaterfacade::new(amp,tuner,dvd,cd, 17 Projector,Screen,Lights,Popper), HomeTheater::watch_movie("Raiders of the Lost Ark"), 20 HomeTheater::end_movie(). Código 4.6.6: Classe principal HomeTheaterTestDrive em ooerlang 4.7 Padrão Flyweight Este padrão de projeto, segundo sua definição, tem por objetivo: Usar compartilhamento para suportar grandes quantidades de objetos refinados eficientemente [Gamma et al., 1994]. Existem casos em que é necessário a um sistema ter que instanciar e gerenciar

118 Padrão Flyweight 98 Figura 4.14: Execução do exemplo para o padrão Facade em Java. uma grande quantidade de objetos. Para uma quantidade muito elevada, o desempenho do sistema pode diminuir, em virtude de um custo elevado de memória utilizada. Para situações como essa que o padrão Flyweight é utilizado. Este padrão pode ser bem aplicado a problemas em que um sistema tenha que utilizar diversas instâncias de objetos, conforme dito anteriormente. Outra característica do padrão Flyweight é que sua utilização depende da possibilidade de se poder substituir muitos grupos de objetos por uma pequena quantidade de objetos compartilhados e, além disso, que o sistema a ser modelado não dependa da identidade do objeto, já que haverá compartilhamento de objetos.

119 Padrão Flyweight 99 Figura 4.15: Execução do exemplo para o padrão Facade em ooerlang Exemplo utilizado para este padrão No exemplo utilizado, retirado de [Truett, 2013], é modelado um sistema para gerenciar um restaurante que serve chás. Este é o único tipo de bebida disponível neste estabelecimento. Entretanto, existem diferentes sabores de chás que podem ser pedidos. Para cada cliente vai existir uma valor representando a mesa utilizada, sendo que qualquer cliente que já estiver presente no restaurante poderá fazer um pedido de um tipo específico de chá. Existe uma classe chamada TeaFlavor, responsável por armazenar o sabor do chá específico para cada instância desta classe. Esta classe também implementa um método da classe abstrata TeaOrder. Outra classe implementada chama-se TeaOrderContext, responsável por armazenar os dados das mesas dos clientes. A classe TeaRestroom possui os dados das mesas dos clientes e dos pedidos realizados. Finalmente a classe TeaFlavorFactory implementa a idéia principal do padrão Fyweight. A figura 4.16 mostra um diagrama de classes deste exemplo. Pode-se obervar que, dependendo dos testes a serem realizados, a quantidade de pedidos pode se tornar muito elevada. Cada pedido de chá é, em teoria, um novo objeto instanciado da classe TeaFlavor. Todavia, este padrão possibilita a reutilização de objetos previamente

120 Padrão Flyweight 100 Figura 4.16: Diagrama de classes do exemplo para o padrão Flyweight. instanciados. Sempre que um tipo de sabor é pedido, o mesmo é armazenado e um objeto deste sabor é instanciado e retornado. Porém se um sabor pedido já tiver sido previamente instanciado, o mesmo é apenas retornado, sem que haja necessidade de instanciação de objetos. Esse controle é realizado na classe TeaFlavorFactory Comparação das implementações em Java e ooerlang Todas as classes mostradas neste exemplo foram implementadas em ooerlang para verificar seu funcionamento em comparação com a implementação em Java. Analisando primeiramente os códigos mostrados em e 4.7.2, que são as implementações em Java e ooerlang da classe TeaFlavor, verifica-se que esta classe possui apenas um atributo, referente ao nome do sabor da bebida pedida, e possui métodos para retornar o sabor da bebida e servir os pedidos realizados. Além dos métodos mostrados, esta classe também possui um construtor para a instan-

121 Padrão Flyweight public class TeaFlavor extends TeaOrder { 2 String teaflavor; 3 4 TeaFlavor(String teaflavor) { 5 this.teaflavor = teaflavor; 6 } 7 8 public String getflavor() { 9 return this.teaflavor; 10 } public void servetea(teaordercontext teaordercontext) { System.out.println("Serving tea flavor " + teaflavor + 15 " to table number " + 16 teaordercontext.gettable()); 17 } 18 } Código 4.7.1: Classe TeaFlavor em Java 1 -class(teaflavor). 2 -extends(teaorder). 3 -export([new/1, get_flavor/0, serve_tea/1]). 4 -constructor([new/1]). 5 6 attributes. 7 8 TeaFlavor methods new(teaflavor) -> 13 self::teaflavor = TeaFlavor get_flavor() -> 16 self::teaflavor serve_tea(teaordercontext) -> 19 io:format("serving tea flavor ~p to table number ~p~n", 20 [self::teaflavor, TeaOrderContext::get_table()]). Código 4.7.2: Classe TeaFlavor em ooerlang ciação de novos sabores (utilizado em sabores ainda não pedidos anteriormente). A classe TeaOrder é uma classe abstrata e possui apenas um método, implementado na classe Tea- Flavor. O método responsável por servir os diferentes tipos de bebidas que foram solicitadas pelos clientes chama-se servetea, recebendo como parâmetro de entrada a mesa na qual este pedido foi realizado.

122 Padrão Flyweight 102 A classe TeaFlavorFactory, mostrada nos códigos e (Java e ooerlang respectivamente), possui como atributos um arranjo que armazena todos os diferentes sabores pedidos pelos clientes. Outro atributo desta classe é a quantidade de chás que foi realmente instanciada, valor diferente da quantidade de chás servidos. O método gettotalteaflavorsmade(), também implementado na classe TeaFlavorFactory, retorna a quantidade de objetos do tipo TeaFlavor de fato instanciada. 1 public class TeaFlavorFactory { 2 TeaFlavor[] flavors = new TeaFlavor[10]; 3 4 int teasmade = 0; 5 6 public TeaFlavor getteaflavor(string flavortoget) { 7 if (teasmade > 0) { 8 for (int i = 0; i < teasmade; i++) { 9 if (flavortoget.equals((flavors[i]).getflavor())) { 10 return flavors[i]; 11 } 12 } 13 } 14 flavors[teasmade] = new TeaFlavor(flavorToGet); 15 return flavors[teasmade++]; 16 } public int gettotalteaflavorsmade() { 19 return teasmade; 20 } 21 } Código 4.7.3: Classe TeaFlavorFactory em Java O método getteaflavor() que recebe como parâmetro de entrada um sabor de chá a ser servido para o cliente, é o responsável por instanciar novos objetos do tipo chá ou reaproveitar objetos anteriormente instanciados. Sempre que este método é invocado, o sabor do chá que é recebido como parâmetro de entrada, é procurado na lista de sabores já instanciados (atributo flavors, arranjo com os tipos de sabores). Se este sabor não for encontrado, o mesmo é instanciado, armazenado na lista de sabores e retornado. Caso o objeto já exista na lista, ele é apenas retornado. Desta forma, mesmo que vários clientes peçam muitos sabores, sendo eles repetidos ou não, a quantidade de objetos a ser instanciada vai ser menor que a quantidade de pedidos, devido aos sabores repetidos. Assim o padrão Flyweight realiza seu objetivo de compartilhar objetos para gerenciar uma grande quantidade de objetos. Isto significa dizer que, havendo

123 Padrão Flyweight class(teaflavorfactory). 2 -export([new/0, get_tea_flavor/1, get_total_tea_flavors_made/0]). 3 -constructor([new/0]). 4 5 attributes. 6 7 Flavors; 8 TeasMade methods new() -> self::flavors = [], self::teasmade = get_tea_flavor(flavortoget) -> 17 TeasMade = self::teasmade, 18 if 19 (TeasMade > 0) -> 20 {Return, Position} = aux_is_item(flavortoget, self::flavors), 21 if 22 (Return == true) -> Flavor = aux_get_item(position, self::flavors), Flavor; 25 true -> 26 {NewList, PositionInserted} = 27 aux_insert_new(flavortoget, self::flavors), 28 Flavor = aux_get_item(positioninserted, NewList), 29 self::flavors = NewList, 30 self::teasmade = self::teasmade+1, 31 Flavor 32 end; true -> {NewList, PositionInserted} = 35 aux_insert_new(flavortoget, self::flavors), 36 Flavor = aux_get_item(positioninserted, NewList), 37 self::flavors = NewList, 38 self::teasmade = self::teasmade+1, 39 Flavor 40 end. Código 4.7.4: Classe TeaFlavorFactory em ooerlang uma quantidade limitada de sabores, assim como diversos pedidos, a quantidade final de objetos instanciada é relativamente pequena, por estar relacionada com os sabores sem repetição e não com a quantidade de pedidos. A classe TeaRestroom possui como atributos dois arranjos, que armazenam tanto os pedidos de cada cliente quanto as mesas referentes a cada pedido realizado. São implementados dois métodos principais, um para retornar a quantidade real de objetos do tipo

124 Padrão Flyweight 104 TeaFlavor que foram instanciados, e outro para gerenciar os diferentes pedidos que são feitos pelos clientes. Os códigos mostrados em e mostram a implementação desta classe (TeaRestroom) em Java e ooerlang respectivamente. 1 public class TeaRestroom { 2 TeaFlavor[] flavors = new TeaFlavor[100]; 3 TeaOrderContext[] tables = new TeaOrderContext[100]; 4 int ordersmade = 0; 5 TeaFlavorFactory teaflavorfactory; 6 7 public void takeorders(string flavorin, int table) { 8 flavors[ordersmade] = teaflavorfactory.getteaflavor(flavorin); 9 tables[ordersmade++] = new TeaOrderContext(table); 10 } public void showtotalteaflavorsmade(){ 13 System.out.println("Total tea Flavor Objects made: 14 " + teaflavorfactory.gettotalteaflavorsmade()); 15 } 16 } Código 4.7.5: Classe TeaRestroom em Java Ao se testar este exemplo, é utilizada a classe principal TestFlyweight. Nesta classe, no método principal, inicialmente são instanciados objetos das classes TeaRestroom e TeaFlavorFactory. Esses objetos são necessários para que se possam realizar os pedidos de chás dos clientes. Em seguida são feitos vários pedidos, para diferentes mesas, utilizando-se do objeto do tipo TeaRestroom. Em seguida, para cada pedido feito é chamado um método responsável por servir os pedidos realizados e, para finalizar, é mostrada a quantidade de objetos do tipo TeaFlavor que foram de fato instanciadas. As figuras 4.17 e 4.18 mostram as execuções em Java e ooerlang, respectivamente. Verifica-se, observando as execuções em Java e ooerlang do exemplo para o padrão de projetos Flyweight que, de fato, foram feitos diversos pedidos para diferentes mesas. Mas, de acordo com a implementação para este padrão, sempre que um pedido requerido já tivesse sido instanciado anteriormente, o mesmo objeto seria devolvido. Dessa forma houve uma economia de memória por parte da aplicação e foi possível verificar que a quantidade real de objetos instanciados é bem inferior à quantidade de pedidos realizados. A extensão orientada a objetos ooerlang mostra-se, de acordo com os resultados obtidos, capaz de implementar o padrão de projetos Flyweight. A execução das implementações

125 Padrão Flyweight class(tearestroom). 2 -export([new/0, take_orders/2, show_total_tea_flavors_made/0]). 3 -constructor([new/0]). 4 5 attributes. 6 7 Flavors; 8 Tables; 9 OrdersMade; 10 TeaFlavorFactory methods new() -> 15 self::flavors = [], 16 self::tables = [], 17 self::ordersmade = 0, 18 self::teaflavorfactory = teaflavorfactory::new() take_orders(flavorin, Table) -> 21 Temp = self::teaflavorfactory, 22 self::flavors = self::flavors ++ [Temp::get_tea_flavor(FlavorIn)], self::tables = self::tables ++ [teaordercontext::new(table)], self::ordersmade = self::ordersmade show_total_tea_flavors_made() -> 27 Temp = self::teaflavorfactory, 28 io:format("total tea Flavor Objects made: ~p~n", 29 [Temp::get_total_tea_flavors_made()]). Código 4.7.6: Classe TeaRestroom em ooerlang em ambas as linguagens apresentou-se obtendo o mesmo resultado. Este padrão está sendo aplicado para gerenciar a instanciação de objetos do tipo TeaFlavor, utilizando-se do compartilhamento de objetos para facilitar a utilização de objetos repetidos sem comprometer o desempenho da aplicação. Caso o padrão de projetos Flyweight não estivesse sendo utilizado, para cada novo pedido de um cliente, independente da mesa do cliente que estivesse solicitando um chá, iria haver uma nova instanciação de objetos. Mesmo que os objetos fossem similares e que não houvesse necessidade de identificação do objeto para com o sistema, eles estariam sendo criados e, dependendo da quantidade de pedidos feitos, o desempenho do sistema poderia estar comprometido. Ao utilizar-se do padrão Flyweight, este problema é contornado. Em alguns casos, na utilização do padrão Flyweight, os objetos que, para o usuário, podem possuir uma quantidade elevada de instâncias, precisam ser salvos de alguma forma.

126 Padrão Proxy 106 Figura 4.17: Execução do exemplo para o padrão Flyweight em Java. Verifica-se, desta forma, as vantagens de se utilizar deste padrão pois, irá haver redução na quantidade real de dados dos objetos compartilhados a serem salvos, tendo como consequência uma economia no espaço de dados a ser utilizado para a persistência de alguma informação de um sistema que se utilize do padrão de projetos Flyweight. 4.8 Padrão Proxy De acordo com sua definição inicial, o padrão de projetos Proxy tem por objetivo principal: Prover um substituto ou ponto através do qual um objeto possa controlar o acesso a outro [Gamma et al., 1994]. Em muitos casos este padrão de projetos é utilizado principalmente quando é necessário que haja uma comunicação remota entre duas máquinas que estejam utilizando um mesmo sistema. A utilização deste padrão tem por finalidade

127 Padrão Proxy 107 Figura 4.18: Execução do exemplo para o padrão Flyweight em ooerlang. principal a de facilitar o controle de acesso entre determinados objetos de um sistema. Semelhante a outros padrões de projeto, o padrão Proxy pode ser utilizado em diferentes situações, mas em todas elas, existem uma ou mais classes que funcionam como sendo um ponto de acesso para determinado objeto. Os principais tipos de objetos Proxy são: Proxy remoto, utilizado para controlar acesso a um objeto remoto, ou seja, localizado em outra máquina, Proxy virtual, que tem por objetivo criar e acessar objetos complexos de forma simplificada e Proxy de proteção, cuja finalidade é controlar o acesso a um objeto original, geralmente possuidor de diferentes direitos de acesso Exemplo utilizado para este padrão Para demonstrar a utilização do padrão Proxy, é utilizado um exemplo retirado de [Books, 2013], no qual é implementado um sistema que simula o carregamento de arquivos de imagem para visualização do usuário. Nesse sistema, são instanciados objetos para receber as imagens a serem carregadas e, dessa forma, o usuário poder visualizá-las. Logicamente, considerando que a implementação deste exemplo é apenas uma simulação da utilização do padrão Proxy, não são utilizadas imagens reais, apenas cadeias de

128 Padrão Proxy 108 caracteres para funcionarem como se fossem imagens carregadas no sistema. A figura 4.19 mostra, com mais detalhes, um diagrama de classes da implementação deste exemplo, para melhor entendimento. Figura 4.19: Diagrama de classes do exemplo para o padrão Proxy Comparação das implementações em Java e ooerlang Conforme pode ser visto pelo diagrama mostrado em 4.19, é implementada uma simples interface chamada Image, com a assinatura de um método que tem por responsabilidade mostrar uma imagem para o usuário ser capaz de visualizar. Este método é implementado por duas classes, RealImage e ProxyImage. Ambas as classes devem possuir a implementação deste método, já que estendem esta interface. Os códigos mostrados em e apresentam as implementações da classe RealImage em Java e ooerlang, nesta ordem. Levando-se em consideração que este exemplo é de um sistema visualizador de imagens que utiliza o padrão de projetos Proxy, percebe-se que, cada objeto que representa uma imagem deve ser instância de uma classe de imagens, neste caso, RealImage. Esta classe representa o objeto imagem propriamente dito. É o objeto que passa a ter seu acesso intermediado pela classe Proxy, que neste exemplo é a classe ProxyImage.

129 Padrão Proxy class RealImage implements Image { 2 3 private String filename = null; 4 5 public RealImage(final String FILENAME) { 6 filename = FILENAME; 7 loadimagefromdisk(); 8 } 9 10 private void loadimagefromdisk() { 11 System.out.println("Loading " + filename); 12 } public void displayimage() { 15 System.out.println("Displaying " + filename); 16 } 17 } Código 4.8.1: Classe RealImage em Java 1 -class(realimage). 2 -implements(image). 3 -export([new/1, load_image_from_disk/0, display_image/0]). 4 -constructor([new/1]). 5 6 attributes. 7 8 Filename methods new(filename) -> 13 self::filename = Filename, 14 load_image_from_disk() load_image_from_disk() -> 17 io:format("loading ~p~n",[self::filename]) display_image() -> 20 io:format("displaying ~p~n", [self::filename]). Código 4.8.2: Classe RealImage em ooerlang A classe RealImage possui como atributo o nome da imagem que cada instância desta classe deve possuir. Além disso, a classe possui um construtor e outros dois métodos. Um deles tem por objetivo simular o carregamento da imagem no disco rígido do computador (loadimagefromdisk()) e o outro é especificamente o método responsável por mostrar a imagem ao usuário (displayimage()). Os códigos mostrados em e mostram a

130 Padrão Proxy 110 implementação em Java e ooerlang da classe ProxyImage. 1 class ProxyImage implements Image { 2 3 private RealImage image = null; 4 private String filename = null; 5 6 public ProxyImage(final String FILENAME) { 7 filename = FILENAME; 8 } 9 10 public void displayimage() { 11 if (image == null) { 12 image = new RealImage(filename); 13 } 14 image.displayimage(); } } Código 4.8.3: Classe ProxyImage em Java 1 -class(proxyimage). 2 -implements(image). 3 -export([new/1, display_image/0]). 4 -constructor([new/1]). 5 6 attributes. 7 8 Image; 9 Filename methods new(filename) -> 14 self::filename = Filename display_image() -> 17 Temp = self::image, 18 if 19 (Temp == []) -> 20 self::image = realimage::new(self::filename); 21 true -> 22 io:format("") 23 end, Temp2 = self::image, Temp2::display_image(). Código 4.8.4: Classe ProxyImage em ooerlang A classe ProxyImage, conforme está especificado na utilização do padrão Proxy, controla o acesso e a utilização dos métodos da classe RealImage. Desta forma, sempre que uma

131 Padrão Proxy 111 imagem for instanciada e posteriormente visualizada pelo usuário, a classe ProxyImage é a intermediadora entre a classe principal e a classe real da imagem (RealImage). Isto significa dizer que as chamadas de métodos utilizados na classe RealImage passam primeiro pela classe ProxyImage. A classe ProxyImage possui dois atributos principais, sendo que um deles é o nome do arquivo de imagem a ser instanciado e posteriormente visualizado, e o outro é uma instância da classe RealImage. Esta classe também possui dois métodos, sendo eles um construtor e o método responsável por mostrar a imagem (displayimage()), chamados pela classe principal. Os códigos mostrados em e apresentam, respectivamente, as implementações da classe principal ProxyExample. 1 class ProxyExample { 2 3 public static void main(string[] args) { 4 final Image IMAGE1 = new ProxyImage("HiRes_10MB_Photo1"); 5 final Image IMAGE2 = new ProxyImage("HiRes_10MB_Photo2"); 6 7 IMAGE1.displayImage(); // loading necessary 8 IMAGE1.displayImage(); // loading unnecessary 9 IMAGE2.displayImage(); // loading necessary 10 IMAGE2.displayImage(); // loading unnecessary 11 IMAGE1.displayImage(); // loading unnecessary 12 } } Código 4.8.5: Classe principal ProxyExample em Java 1 -class(proxyexample). 2 -export([main/0]). 3 4 class_methods. 5 6 main() -> 7 Image1 = proxyimage::new("hires_10mb_photo1"), 8 Image2 = proxyimage::new("hires_10mb_photo2"), 9 10 Image1::display_image(), %%loading necessary Image1::display_image(), Image2::display_image(), %%loading unnecessary %%loading necessary 13 Image2::display_image(), %%loading unnecessary 14 Image1::display_image(). %%loading unnecessary Código 4.8.6: Classe principal ProxyExample em ooerlang

132 Padrão Proxy 112 Nesta classe principal inicialmente são instanciados dois objetos que representam dois arquivos de imagem a terem sua visualização simulada por meio da utilização do padrão Proxy. Após as devidas instanciações, o método displayimage(), cujas classes RealImage e ProxyImage implementam, é utilizado seguidamente para verificar o funcionamento do simulador de visualização de imagens. A classe ProxyImage sempre que recebe uma chamada do método displayimage(), verifica se a instância referente à imagem real já foi criada. Em caso negativo, esta classe instancia um novo objeto da classe RealImage, passando por parâmetro o nome do arquivo correspondente à imagem. Se o objeto referente à imagem já tiver sido previamente instanciado, o objeto ProxyImage apenas repassa a responsabilidade de mostrar a imagem ao objeto da classe RealImage. A execução desta classe é mostrada em Java e ooerlang pelas figuras mostradas em 4.20 e Figura 4.20: Execução do exemplo para o padrão Proxy em Java.

133 Padrão Proxy 113 Figura 4.21: Execução do exemplo para o padrão Proxy em ooerlang. Na classe RealImage, sempre que um objeto novo for instanciado, antes de ele poder ser visualizado, o mesmo deverá ser carregado em disco. Isto é simulado dentro do construtor da classe RealImage. Neste construtor é realizada a chamada do método loadimagefromdisk(), sendo que, a partir da segunda chamada de visualização de imagens, este carregamento em disco não é mais necessário. Portanto, as imagens a serem testadas devem possuir apenas um carregamento antes das respectivas visualizações. Diversas são as situações em que é possível e até mesmo necessário utilizar o padrão de projetos Proxy. Este padrão de projetos é mais comumente utilizado em sistemas que necessitem ter acesso remoto a outra máquina, e manipular objetos muito complexos. E para facilitar este trabalho, é utilizada uma classe intermediária, que faz o papel de representar de forma simplificada o objeto a ser acessado, reduzindo erros de comunicação na execução do referido sistema. Tratando-se deste exemplo, verificou-se outra forma de se utilizar o padrão Proxy. Neste caso, o usuário possui um sistema visualizador de imagens, e tem por objetivo visualizálas da forma mais eficiente possivel. Porém, sempre que uma imagem é visualizada, ela deve primeiramente ser carregada na memória volátil do computador. Utilizando-se deste

134 Conclusões dos Padrões de Projeto Estruturais em ooerlang 114 padrão, implementou-se um objeto intermediário para tratar das visualizações, assim como o usuário pode verificar quando uma imagem está sendo carregada pela primeira vez. Algumas consequências podem ser verificadas na utilização do padrão Proxy. Em se tratando de sistemas com acesso remoto, uma classe Proxy remota consegue esconder o fato de que o objeto acessado reside em um diferente endereço eletrônico. Em se tratando de um Proxy virtual (caso do exemplo utilizado), é possível realizar otimizações na criação de diversos objetos. Em relação a um Proxy de proteção, verifica-se um melhor controle de segurança ao objeto que está sendo acessado por intermédio da classe Proxy. 4.9 Conclusões dos Padrões de Projeto Estruturais em ooerlang Conforme demonstrado nos exemplos utilizados para implementar os padrões de projeto estruturais, verifica-se que a característica principal deste tipo de padrão tem por objetivo básico se preocupar com a forma com que os objetos são compostos para criar estruturas maiores. Um padrão que pode ser citado nesta característica é o Adapter, em que é necessário criar uma classe para adaptar interfaces inicialmente incompatíveis, tornando o sistema mais estruturado e consequentemente maior. Para todas as implementações obtidas em Java, é gerada uma implementação similar em ooerlang, com a mesma quantidade de classes para ambas as abordagens. As características de sintaxe do ooerlang assim como suas ferramentas que permitem a utilização de elementos da orientação à objetos, permitem a escrita de fontes sintaticamente parecidos, mas não iguais, uma vez que o ooerlang foi desenvolvido com base no Erlang, possuindo as características próprias desta linguagem funcional. Para todos os sete (7) padrões de projeto estruturais implementados, compilados e testados em ooerlang, o resultado das execuções mostrou-se igual às execuções em Java. Desta forma, os comportamentos esperados em ooerlang são os obtidos, uma vez que não diferiram das implementações que haviam sido anteriormente obtidas em Java. Portanto, para aplicações que necessitem utilizar elementos e características dos padrões de projeto estruturais, o ooerlang demonstra ser uma ferramenta bastante útil e eficaz.

135 Capítulo 5 Padrões de Projeto Comportamentais Neste capítulo são estudados os últimos onze (11) padrões de projetos definidos por [Gamma et al., 1994]. Tratam-se dos padrões de projeto comportamentais. A quantidade de padrões comportamentais é maior, pois existem mais situações em que estes padrões podem ser aplicados. Para cada padrão é utilizado um exemplo prático, cuja modelagem em Java e ooerlang é comparada, assim como a sintaxe. Alguns códigos-fonte são apresentados, da mesma forma, a execução para cada padrão de projetos também é mostrada, observando os resultados obtidos com a utilização da extensão ooerlang. 5.1 Conceitos Iniciais Os padrões de projeto comportamentais preocupam-se com algoritmos e com a delegação de responsabilidades entre objetos [Gamma et al., 1994]. Conforme suas características próprias, os padrões de projetos comportamentais tem foco não somente com as classes ou objetos, mas principalmente, com a comunicação entre esses objetos. Em situações onde é difícil verificar o funcionamento de um sistema em tempo de execução, os padrões de projeto comportamentais podem ser utilizados para gerenciar o fluxo de informações entre os objetos. Nas ocasiões em que os padrões de projeto comportamentais são aplicados nas classes de um determinado sistema, geralmente é utilizado o conceito de herança com o obje-

136 Padrão Chain of Responsibility 116 tivo de distribuir um determinado comportamento entre as classes. Esta é uma forma de abordagem que evidencia uma das principais características dos padrões de projeto comportamentais, que é o foco na forma como os objetos em um determinado sistema estão interconectados. Os conceitos dos padrões de projeto comportamentais ao serem aplicados a objetos, mostram que a herança já não é muito utilizada, em detrimento da composição de objetos. Alguns desses padrões com foco nos objetos, implementam soluções em que um pequeno grupo de objetos interconectados é trabalhado em seu comportamento para realizar uma tarefa na qual apenas um objeto não seria capaz de realizar. Outros padrões de projetos comportamentais preocupam-se em encapsular um comportamento em um objeto e delegar requisições a ele [Gamma et al., 1994]. Todos os códigos-fonte deste capítulo podem ser encontrados em [GitHub, 2008]. 5.2 Padrão Chain of Responsibility Analisando-se sua original definição, o padrão de projetos Chain of Responsibility tem por objetivo principal: Evitar acoplar o remetente de uma requisição ao seu destinatário ao dar a mais de um objeto a chance de servir à requisição. Compõe os objetos em cascata e passa a requisição pela corrente até que um objeto a sirva. Verifica-se que este padrão pode ser bem utilizado em sistemas que precisem possuir diferentes objetos para tratar de diferentes requisições, com diferentes respostas. Portanto, o padrão de projetos Chain of Responsibility pode ser utilizado em casos onde mais de um objeto pode atender a uma requisição, sendo que este objeto não é especificado. Este padrão também é utilizável quando, por exemplo, seja necessário delegar uma requisição a apenas um de diversos objetos, sem que este objeto seja especificado explicitamente. Outra situação na qual este padrão pode ser utilizado é quando o conjunto de objetos responsável por atender a uma requisição deve ser especificado em tempo de execução.

137 Padrão Chain of Responsibility Exemplo utilizado para este padrão O exemplo utilizado para exemplificar o padrão de projetos Chain of Responsibility foi retirado de [Kulandai, 2012], e trata-se de um sistema que analisa valores numéricos inteiros. Esse sistema recebe como entrada um valor numérico e analisa este valor com relação ao seu sinal. Desta forma, a saída do programa corresponde ao tipo de sinal do valor numérico de entrada. Para que este padrão possa ser utilizado, existe a necessidade de se implementar a corrente de responsabilidades que caracteriza este padrão. Desta forma, são modeladas as classes NegativeProcessor, PositiveProcessor e ZeroProcessor. Estas são as correspondentes classes que podem processar os valores de entrada. A figura mostrada em 5.1 apresenta com detalhes o diagrama de classes deste exemplo para melhor entendimento. Figura 5.1: Diagrama de classes do exemplo para o padrão Chain of Responsibility. Observa-se que está sendo utilizada uma interface chamada Chain. Esta interface, com maior nível de abstração, é implementada pelas subclasses que compõem a corrente de responsabilidades presente no padrão. Portanto, para que uma requisição seja processada, ela deve ser utilizada ao longo da corrente de responsabilidades. Cada instância das classes NegativeProcessor, PosiviteProcessor e ZeroProcessor, recebe a requisição do usuário e, em

138 Padrão Chain of Responsibility 118 seguida, processa ou passa esta requisição para o elo seguinte da corrente. A classe Number refere-se às requisições de entrada, que são valores numéricos inteiros positivos, negativos ou nulos Comparação das implementações em Java e ooerlang A utilização do padrão de projetos Chain of Responsibility e sua aplicação neste exemplo é verificada justamente na utilização das classes que implementam a interface Chain. Estas classes são as que, de fato, realizam o trabalho especificado na definição do padrão que corresponde a uma corrente de responsabilidades. A interface Chain, mostrada nos códigos e (Java e ooerlang respectivamente), apresenta as assinaturas de dois métodos implementados nas subclasses que representam a corrente de responsabilidades. 1 public interface Chain { 2 3 public abstract void setnext(chain nextinchain); 4 5 public abstract void process(number request); 6 } Código 5.2.1: Interface Chain em Java 1 -interface(chain). 2 -export([set_next/1, process/1]). 3 4 methods. 5 6 set_next(nextinchain). 7 process(request). Código 5.2.2: Interface Chain em ooerlang O método da interface Chain são setnext() e process(). O primeiro recebe como parâmetro uma instância das classes que implementam os elos da corrente, podendo ser NegativeProcessor, PositiveProcessor e ZeroProcessor. Este método (setnext()) tem por objetivo o de estruturar a corrente a ser implementada, configurando a ordem dos elos da referida corrente. Já o método process() tem o objetivo de processar determinada requisição em um dos elos da corrente, recebendo como parâmetro de entrada o valor numérico

139 Padrão Chain of Responsibility 119 da requisição. As classes que implementam a interface Chain, possuem uma estrutura de implementação semelhante. A diferença principal entre estas classes está no método process() de cada uma. Os códigos mostrados em e mostram as implementações da classe PositiveProcessor em Java e ooerlang, nesta ordem. Verifica-se que esta classe (assim como as outras que implementam a interface Chain), possuem um atributo, chamado nextinchain. Este atributo refere-se ao próximo elo da corrente de responsabilidades. 1 public class PositiveProcessor implements Chain { 2 3 private Chain nextinchain; 4 5 public void setnext(chain c) { 6 nextinchain = c; 7 } 8 9 public void process(number request) { 10 if (request.getnumber() > 0) { 11 System.out.println("PositiveProcessor : " } else { request.getnumber()); 14 nextinchain.process(request); 15 } 16 } 17 } Código 5.2.3: Classe PositiveProcessor em Java O atributo da classe PositiveProcessor, de nome nextinchain, e que também está presente nas outras classes que implementam a interface Chain, é do tipo Chain, portanto, pode ser representado por qualquer instância das subclasses da interface Chain. Este atributo é utilizado na implementação do método setnext(), recebendo como parâmetro de entrada uma instância a ser o próximo elo da corrente responsável por processar as requisições de entrada. No método process() encontra-se a diferença principal das implementações da interface Chain. Em relação à classe PositiveProcessor, este método, ao receber como parâmetro de entrada a requisição a ser processada, faz uma verificação deste valor numérico de entrada. O resultado desta verificação define se esta requisição vai ser processada no elo atual da corrente ou se vai ser passada ao próximo elo. A definição do elo da corrente é mostrada na classe principal chamada TestChain, implementada em Java e ooerlang e apresentada,

140 Padrão Chain of Responsibility class(positiveprocessor). 2 -implements(chain). 3 -export([set_next/1, process/1]). 4 5 attributes. 6 7 NextInChain. 8 9 methods set_next(c) -> 12 self::nextinchain = C process(request) -> 15 Number = Request::get_number(), 16 if 17 (Number > 0) -> 18 io:format("positiveprocessor: ~p~n", [Number]); 19 true -> 20 Next = self::nextinchain, 21 Next::process(Request) 22 end. Código 5.2.4: Classe PositiveProcessor em ooerlang respectivamente, nos códigos e public class TestChain { 2 public static void main(string[] args) { 3 // configure Chain of Responsibility 4 Chain c1 = new NegativeProcessor(); 5 Chain c2 = new ZeroProcessor(); 6 Chain c3 = new PositiveProcessor(); 7 c1.setnext(c2); 8 c2.setnext(c3); 9 10 // calling chain of responsibility 11 c1.process(new Number(99)); 12 c1.process(new Number(-30)); 13 c1.process(new Number(0)); 14 c1.process(new Number(100)); } } Código 5.2.5: Classe principal TestChain em Java Observando-se a implementação realizada na classe principal TestChain, tanto em Java quanto em ooerlang, verifica-se que, inicialmente são instanciados três (3) objetos, pertencentes respectivamente às classes NegativeProcessor, ZeroProcessor e, finalmente, Positi-

141 Padrão Chain of Responsibility class(testchain). 2 -export([main/0]). 3 4 class_methods. 5 6 main() -> 7 %%Configure chain of Responsibility 8 C1 = negativeprocessor::new_(), 9 C2 = zeroprocessor::new_(), 10 C3 = positiveprocessor::new_(), 11 C1::set_next(C2), 12 C2::set_next(C3), %%Calling chain of responsibility 15 C1::process(number::new(99)), 16 C1::process(number::new(-30)), 17 C1::process(number::new(0)), 18 C1::process(number::new(100)). 19 Código 5.2.6: Classe principal TestChain em ooerlang veprocessor. Em seguida a estrutura da corrente de responsabilidades é organizada com a utilização do método setnext. Desta forma, o primeiro elo da corrente vai ser a instância de NegativeProcessor, seguida de ZeroProcessor, finalizando com PositiveProcessor. Após as devidas instanciações e estruturações dos elos da corrente em relação à ordem de processamento das requisições, o passo seguinte é o de realizar as requisições de entrada. Para tal são feitos testes que comprovem se o processamento nos elos está correto. São passados quatro valores numéricos, de tal forma que todos os objetos a tratar das requisições tenham que processá-la ao menos uma vez. Desta forma verifica-se a comprovação da utilização do padrão Chain of Responsibility. As imagens mostradas em 5.2 e 5.3 mostram as execuções das implementações em Java e ooerlang, respectivamente. Verificando-se o resultado das execuções das implementações em Java e ooerlang, observa-se que ambas as abordagens resultaram na mesma saída. Desta forma, em ambas as linguagens, todas as requisições foram passadas de elo em elo da corrente de responsabilidades, até que chegassem ao elo que pudesse processar a requisição. Analisando as implementações da classe principal TestChain, percebe-se que sempre as requisições irão inicialmente ser passadas ao primeiro elo da corrente, NegativeProcessor. Ao receber uma requisição, a classe ZeroProcessor, mediante o método process(), verifica se este valor numérico recebido é negativo. Se for, é feito o processamento nesta mesma

142 Padrão Chain of Responsibility 122 Figura 5.2: Execução do exemplo para o padrão Chain of Responsibility em Java. classe. Caso não seja, esta requisição simplesmente é passada para o elo seguinte da corrente por meio do atributo nextinchain. É importante notar que cada elo não tem conhecimento do elo seguinte, apenas repassa a responsabilidade para o próximo objeto processador da corrente. A extensão da linguagem de programação Erlang para suporte à orientação a objetos, ooerlang, demonstrou por meio de uma implementação similar a um exemplo em Java do padrão Chain of Responsibility, resultado semelhante ao encontrado na própria implementação em Java. Este exemplo, conforme a definição deste padrão de projeto, teve como objetivo principal o de desacoplar uma requisição de seu destinatário, abrindo possibilidades para que mais de um destinatário pudesse atender a uma determinada requisição. Na utilização do padrão Chain of Responsibility, ao ser estruturada uma corrente para atender a diversas requisições distintas, é possível fazer com que o último elo da corrente seja

143 Padrão Command 123 Figura 5.3: Execução do exemplo para o padrão Chain of Responsibility em ooerlang. responsável por atender a uma requisição que não se encaixe em nenhum dos elos anteriores da corrente. Neste exemplo simplificado, foi considerado que todas as requisições seriam valores numéricos inteiros (não importando o sinal). Desta forma não existiu a necessidade de utilizar um elo para casos de excessão. Mas é possível e até recomendável utilizar um elo que processe situações não esperadas. 5.3 Padrão Command Verificando-se a definição deste padrão de projeto, o padrão Command tem por objetivo principal: Encapsular uma requisição como um objeto, permitindo que clientes parametrizem diferentes requisições, filas ou requisições de log, e suportar operações reversíveis [Gamma et al., 1994]. Desta forma é possivel utilizar vários comandos diferentes, de forma que exista um desacoplamento entre quem realiza a requisição de uma ação e o objeto que, de fato, realiza a referida ação. Assim é possível realizar um ação sem precisar saber a ação realizada nem o recebedor da ação. Desta forma, o padrão de projetos Command pode ser bem utilizado em situações

144 Padrão Command 124 onde seja necessário parametrizar objetos em relação a ações que precisem ser realizadas. Também pode ser aplicado a sistemas em que seja importante especificar listas de comandos e executá-los em momentos diferentes. Uma outra característica importante do padrão Command é a possibilidade de suportar operações reversíveis, de tal forma que uma ação realizada por último possa ser desfeita, assim como suportar registro de ações, para que seja possível recuperar um estado do sistema se houver uma súbita falha, por exemplo Exemplo utilizado para este padrão Para ilustrar a utilização do padrão de projetos Command, é utilizado um exemplo retirado de [Freeman et al., 2004], no qual é implementado um controlador que automatiza diversos dispositivos de uma casa. É um controlador universal programável que pode gerenciar o funcionamento de equipamentos, assim como permitir operações reversíveis, semelhante ao que é determinado pela definição deste padrão de projeto. Este controle de automação residencial pode ser programado para que cada botão seja configurado a um tipo de ação, de acordo com a necessidade do cliente. Neste exemplo simplificado, as ações do controle estão voltadas para dois principais elementos controláveis: As luzes do ambiente e o ventilador de teto da casa. Mas para cada um desses dispositivos existe uma série de comandos, como por exemplo, ligar luz, desligar luz, etc. Cada diferente comando é modelado como sendo um objeto que passa a encapsular um método chamado execute(), responsável por executar o referido comando. A figura 5.4 mostra com mais detalhes um diagrama de classes para este exemplo. As classes sobrepostas possuem implementação similar às classes que as sobrepõem. Verifica-se ao observar a figura 5.4 que nove (9) comandos foram implementados, ou seja, nove classes cujas instâncias devem encapsular uma determinada ação foram modeladas. Dessas nove, quatro (4) comandos são específicos para as luzes da casa e quatro (4) outros destinam-se a controlar o ventilador de teto. O comando restante não realiza nenhuma ação. Todas as classes cujas instâncias devem encapsular um comando estão implementando uma interface em comum, de nível abstrato mais elevado, chamada Command, que possui os métodos para executar a ação e desfazer a última ação realizada.

145 Padrão Command 125 Figura 5.4: Diagrama de classes do exemplo para o padrão Command Comparação das implementações em Java e ooerlang Para cada um dos dispositivos comandados pelo controlador modelado no sistema exposto no presente exemplo, é implementada uma classe que armazena os dados referentes aos dispositivos. No caso das luzes da casa, a classe criada se chama Light, e no caso dos ventiladores de teto, chama-se CeilingFan. Assim sendo, cada uma das classes que implementa a interface Command, atua em um dos dispositivos controlados na casa, podendo estar relacionado a uma luz ambiente ou a um dos ventiladores de teto da residência. As classes que realizam comandos específicos para o controle de luzes são LightOnCom-

146 Padrão Command 126 mand, LightOffCommand, DimmerLightOnCommand, DimmerLightOffCommand. Em relação aos comandos que controlam os ventiladores de teto da casa, temos os comandos CeilingFanHighCommand, CeilingFanLowCommand, CeilingFanMediumCommand e CeilingFanOffCommand. O nome de cada classe está relacionado com o comando da mesma. Para as luzes os comandos são de ligar, desligar e controlar a intensidade de luz. Para os ventiladores de teto é possível ajustar para intensidade alta, média, baixa ou desligado. A classe LightOnCommand, implementada em Java e ooerlang está mostrada nos códigos e respectivamente. Esta classe possui dois atributos principais, light (referente à classe Light) e level, que armazena o nível de intensidade de luz. Como esta é uma das classes que implementa a interface Command, são implementados os métodos execute() para realizar a execução do comando ligar luz e o método undo que retorna ao nível anterior de intensidade de luz. 1 public class LightOnCommand implements Command { 2 Light light; 3 int level; 4 public LightOnCommand(Light light) { 5 this.light = light; 6 } 7 8 public void execute() { 9 10 level = light.getlevel(); light.on(); 11 } public void undo() { 14 light.dim(level); 15 } 16 } Código 5.3.1: Classe LightOnCommand em Java A utilização do método que possibilita operações reversíveis (undo) é possivel pelo fato de que, sempre ao se utilizar o comando para ligar a luz de determinado ambiente na residência, o nível atual de luz é armazenado no atributo level. Se, porventura, esse nível mudar na utilização de outro comando e, seja necessário retornar ao nível anterior, este nível (que já vai estar armazenado) poderá ser recuperado. Todos os comandos implementados para este exemplo funcionam de forma semelhante. Em relação aos comandos que tratam do ventilador de teto, o comando para desfazer uma operação armazena a última intensidade

147 Padrão Command class(lightoncommand). 2 -implements(command). 3 -export([new/1, execute/0, undo/0]). 4 -constructor([new/1]). 5 6 attributes. 7 8 Light; 9 Level methods new(light) -> 14 self::light = Light execute() -> 17 Temp = self::light, 18 self::level = Temp::get_level(), 19 Temp::on() undo() -> 22 Temp = self::light, 23 Temp::dim(self::Level). Código 5.3.2: Classe LightOnCommand em ooerlang de ventilação configurada. A classe que armazena as características dos dispositivos de luz da residência estão armazenadas na classe Light. É nesta classe que armazena-se o nível atual de luz configurada. Nos objetos que funcionam como comando, o nível de luz utilizado é necessariamente recuperado da classe Light. Sempre que for feita uma nova instância da classe Light, e for utilizado um comando de ligar luz, o nível de intensidade da luz já é inicializado automaticamente. Os códigos mostrados em e mostram, respectivamente, as implementações em Java e ooerlang da classe Light Conforme pode ser observado, a classe Light possui um construtor, um método que permite ligar a luz, outro método que permite desligar a luz, assim como um terceiro método que possibilita modificar a intensidade da luz. Estes métodos não são utilizados diretamente pelo usuário, e sim por meio do controle remoto. Este controle remoto pode ser configurado de acordo com os comandos implementados para controle de luz e circulação de ar. E é por meio dos objetos que funcionam como se fossem os próprio comandos que os métodos na classe Light são utilizados.

148 Padrão Command public class Light { 2 String location; 3 int level; 4 5 public Light(String location) { 6 this.location = location; 7 } 8 9 public void on() { 10 level = 100; 11 System.out.println("Light is on"); 12 } public void off() { 15 level = 0; 16 System.out.println("Light is off"); 17 } public void dim(int level) { 20 this.level = level; 21 if (level == 0) { 22 off(); } else { 25 System.out.println("Light is dimmed to " + level + "%"); 26 } 27 } public int getlevel() { 30 return level; 31 } 32 } Código 5.3.3: Classe Light em Java A classe RemoteControlWithUndo é a classe que implementa as características próprias do controle remoto que passa a possuir os comandos já definidos pelo usuário. A instância de um objeto desta classe vai ser o controle remoto utilizado para, inicialmente configurar onde cada comando é utilizado e, posteriormente, ser a ferramenta que permite executar os comandos nele inseridos. Os códigos mostrados em e apresentam os detalhes principais das implementações em Java e ooerlang, nesta ordem, da classe RemoteControlWithUndo. Observa-se que a classe RemoteControlWithUndo possui três (3) atributos principais. Os dois primeiros são duas listas de sete (7) elementos. Cada lista pertence a uma classe de comandos. Uma lista para os comandos que ligam certo dispositivo e outra lista para os comandos que desligam. O terceiro atributo refere-se ao comando undo, ou desfazer.

149 Padrão Command class(light). 2 -export([new/1, on/0, off/0, dim/1, get_level/0]). 3 -constructor([new/1]). 4 5 attributes. 6 7 Location; 8 Level methods new(location) -> 13 self::location = Location on() -> 16 self::level = 100, 17 io:format("light is on ~n") off() -> 20 self::level = 0, 21 io:format("light is off ~n") dim(level) -> self::level = Level, 25 if 26 (Level == 0) -> 27 off(); 28 true -> 29 io:format("light is dimmed to ~p % ~n", [Level]) 30 end get_level() -> 33 self::level. Código 5.3.4: Classe Light em ooerlang O construtor desta classe (RemoteControlWithUndo, não mostrado nas implementações) inicializa todos os slots de memória com o comando NoCommand. Isto simula um controle remoto com as configurações de fábrica. O método setcommand da classe RemoteControlWithUndo é abstraído dos fontes mostrados em e 5.3.6, e têm como objetivo, o de configurar cada slot do controle remoto com um comando específico. Os métodos onbuttonwaspushed e offbuttonwaspushed realizam a execução do comando que foi previamente configurado para o correspondente slot (passado por parâmetro). Se não houver comando configurado, nenhuma ação é realizada, de acordo com a implementação da classe NoCommand. A classe principal, RemoteLoader é a classe utilizada para inicializar e configurar o con-

150 Padrão Command public class RemoteControlWithUndo { 2 Command[] oncommands; 3 Command[] offcommands; 4 Command undocommand; 5 6 public void onbuttonwaspushed(int slot) { 7 oncommands[slot].execute(); 8 undocommand = oncommands[slot]; 9 } public void offbuttonwaspushed(int slot) { 12 offcommands[slot].execute(); } undocommand = offcommands[slot]; public void undobuttonwaspushed() { 17 undocommand.undo(); 18 } Código 5.3.5: Classe RemoteControlWithUndo em Java 1 -class(remotecontrolwithundo). 2 -export([new/0, set_command/3, on_button_was_pushed/1, off_button_was_pushed/1]). 3 -export([undo_button_was_pushed/0, to_string/0]). 4 -constructor([new/0]). 5 6 attributes. 7 8 OnCommands; 9 OffCommands; 10 UndoCommand methods on_button_was_pushed(slot) -> 15 Temp = aux_get_element(slot, self::oncommands), 16 Temp::execute(), 17 self::undocommand = Temp off_button_was_pushed(slot) -> 20 Temp = aux_get_element(slot, self::offcommands), 21 Temp::execute(), 22 self::undocommand = Temp undo_button_was_pushed() -> 25 Temp = self::undocommand, 26 Temp::undo(). Código 5.3.6: Classe RemoteControlWithUndo em ooerlang trole remoto, assim como testar a execução deste exemplo. Os códigos mostrados em 5.3.7

151 Padrão Command 131 e mostram os detalhes relevantes da implementação da classe principal deste exemplo em Java e ooerlang, respectivamente. 1 public class RemoteLoader { 2 3 public static void main(string[] args) { 4 RemoteControlWithUndo remotecontrol = 5 new RemoteControlWithUndo(); 6 7 Light livingroomlight = new Light("Living Room"); 8 9 LightOnCommand livingroomlighton = 10 new LightOnCommand(livingRoomLight); 11 LightOffCommand livingroomlightoff = 12 new LightOffCommand(livingRoomLight); remotecontrol.setcommand(0, livingroomlighton, 15 livingroomlightoff); remotecontrol.onbuttonwaspushed(0); 18 remotecontrol.offbuttonwaspushed(0); 19 System.out.println(remoteControl); 20 remotecontrol.undobuttonwaspushed(); 21 remotecontrol.offbuttonwaspushed(0); 22 remotecontrol.onbuttonwaspushed(0); 23 System.out.println(remoteControl); 24 remotecontrol.undobuttonwaspushed(); 25 } 26 } Código 5.3.7: Classe principal RemoteLoader em Java O método principal da classe RemoteLoader (main), inicialmente instancia um objeto da classe RemoteControlWithUndo, para ser o objeto representante do controle remoto em si. Depois é instanciado um objeto do tipo Light, para que possa haver controle das luzes de determinado ambiente. Em seguida são instanciados dois objetos que funcionam como comandos de controle das luzes (LightOnCommand e LightOffCommand). Por último estes dois comandos são configurados nas posições iniciais do controle. Após as configurações, os botões são testados, e entre os testes dos botões, também é impresso o status atual do controle remoto, ou seja, quais comados estão configurados em quais botões. O botão responsável por desfazer uma ação (undo) também é testado, para verificar se sua execução ocorre de acordo com o esperado. As figuras mostradas em 5.5 e 5.6 mostram com detalhes o resultado dos testes realizados em Java e ooerlang, nesta sequência.

152 Padrão Command class(remoteloader). 2 -export([main/0]). 3 4 class_methods. 5 6 main() -> 7 RemoteControl = remotecontrolwithundo::new(), 8 9 LivingRoomLight = light::new("living Room"), LivingRoomLightOn = lightoncommand::new(livingroomlight), LivingRoomLightOff = lightoffcommand::new(livingroomlight), RemoteControl::set_command(0, LivingRoomLightOn, LivingRoomLightOff), RemoteControl::on_button_was_pushed(0), 18 RemoteControl::off_button_was_pushed(0), 19 RemoteControl::to_string(), 20 RemoteControl::undo_button_was_pushed(), 21 RemoteControl::off_button_was_pushed(0), 22 RemoteControl::on_button_was_pushed(0), RemoteControl::to_string(), RemoteControl::undo_button_was_pushed(). Código 5.3.8: Classe principal RemoteLoader em ooerlang Verifica-se que, ao serem pressionados os botões relacionados com a ação de ligar e desligar as luzes de determinado ambiente da residência, as mensagens de retorno esperadas são mostradas, comprovando que a execução realizou-se da forma como estava prevista. Assim, de acordo com a definição do padrão de projetos Command, também é possivel verificar quais são os comandos atualmente configurados no controle remoto, em todas as posições válidas, e também na posição referente ao comando de desfazer uma ação (undo). Comprovou-se, utilizando-se de uma aplicação implementada em Java que uma implementação desta mesma aplicação em ooerlang resulta no mesmo comportamento de saída. A extensão do Erlang para orientação a objetos permite que sejam utilizados sistemas com as principais características da utilização do padrão de projetos Command. Isto significa dizer que o ooerlang permite que objetos sejam utilizados para encapsular ações em um sistema, de tal forma que exista um conjunto de objetos funcionando como métodos de comando para determinada situação. No exemplo prático demonstrado, é modelado um sistema de automação residencial. As ações de comando de todo o sistema são implementadas por meio de um controle

153 Padrão Command 133 Figura 5.5: Execução do exemplo para o padrão Command em Java. residencial. Este controle possui dois pares de botões para cada dispositivo da casa, um para ligar e outro para desligar. Além disso, existe um botão geral com o simples objetivo de desfazer uma última ação realizada. Desta forma todas as características do padrão Command foram de fato implementadas. Verifica-se que, com a utilização do padrão de projetos Command, é possivel desacoplar o objeto que invoca um comando do objeto que realiza a ação especificada. Como cada comando é modelado de forma a ser um objeto, os comandos podem ser manipulados e estendidos como qualquer outro objeto. Em situações onde seja necessário incluir novos comandos, o padrão Command mostra-se bastante versátil e flexível, pois não é necessário modificar nenhum código-fonte já existente para relizar esta ação, sendo necessário apenas criar um novo objeto com esta finalidade.

154 Padrão Interpreter 134 Figura 5.6: Execução do exemplo para o padrão Command em ooerlang. 5.4 Padrão Interpreter O padrão de projetos Interpreter, de acordo com sua principal definição, tem o objetivo de: Dada uma linguagem, definir uma representação para sua gramática junto com um interpretador que usa a representação para interpretar sentenças na linguagem [Gamma et al., 1994]. Este padrão pode ser bem utilizado quando seja necessário criar gramáticas de linguagens de programação com uma quantidade de regras limitada, assim como quando seja possível e até mesmo necessário modelar um problema como uma gramática simplificada. O padrão de projetos Interpreter é possível de ser utilizado quando existe a necessidade de interpretar uma linguagem e, ao mesmo tempo, seja possível representar as declarações de determinada gramática por meio de árvores sintáticas. É mais recomendável utilizar o padrão Interpreter em situações onde a gramática é simples, pois para uma gramática muito extensa, sua hierarquia de classes torna-se grande e de difícil gerenciamento. Na utilização deste padrão, é importante ressaltar que a eficiência de execução não é o ponto principal, e sim a solução de determinado problema.

155 Padrão Interpreter Exemplo utilizado para este padrão Para melhor compreensão da utilização do padrão Interpreter, é utilizado um exemplo retirado de [Books, 2013] que aplica o conceito deste padrão de projeto. É implementado um sistema simplificado que interpreta a gramática de uma linguagem responsável por calcular problemas de aritmética simples. Trata-se de uma gramática para uma linguagem em que é possivel utilizar variáveis e cálculos que envolvam soma e subtração de valores inteiros. Desta forma, para este exemplo é modelada uma classe para cada regra da gramática desenvolvida. Em se tratando de cálculos que envolvam o operador de subtração, utiliza-se a classe Minus. Para cálculos que possuam elementos de soma, foi também utilizada uma classe, chamada Plus. Cada valor numérico desta gramática é armazenado em variáveis literais, e para cada uma dessas variáveis é modelada uma classe chamada Variables. Para melhor entendimento das relações entre as classes, a figura 5.7 mostra um diagrama de classes deste exemplo. Observa-se, por meio da figura 5.7, que é utilizada uma interface chamada Expression. Esta interface possui a abstração do método interpret(), tratando-se do método principal deste padrão. Cada uma das classes que representa uma regra nesta gramática implementa o método interpret() que possui as características próprias de sua regra específica. Também é possivel observar a classe Number, que tem por objetivo passar valores numéricos para as variáveis da expressão Comparação das implementações em Java e ooerlang As classes Plus, Minus, Variable e Number possuem características semelhantes. A diferença principal são os atributos das mesmas. No caso das classes Variable e Number, existe apenas um atributo, referente à variável ou a um valor numérico de uma variável. Já em relação às classes Plus e Minus, existem dois atributos que referem-se aos dois operandos da operação que estas classes realizam, o operando da esquerda e o operando da direita. Para melhor entendimento, os códigos mostrados em e mostram, respectivamente, as implementações em Java e ooerlang da classe Plus. Verifica-se que, assim como todas as classes que implementam a interface Expression, a

156 Padrão Interpreter 136 Figura 5.7: Diagrama de classes do exemplo para o padrão Interpreter. 1 public class Plus implements Expression { 2 Expression leftoperand; 3 Expression rightoperand; 4 public Plus(Expression left, Expression right) { 5 leftoperand = left; 6 rightoperand = right; 7 } public int interpret(map<string,expression> variables) return leftoperand.interpret(variables) + { 11 rightoperand.interpret(variables); 12 } 13 } Código 5.4.1: Classe Plus em Java classe Plus possui seus atributos, um construtor e a implementação do método interpret(). Este método recebe como parâmetro de entrada uma tabela com as variáveis e seus respectivos valores. Em Java este parâmetro é implementado por meio de uma tabela hash e

157 Padrão Interpreter class(plus). 2 -implements(expression). 3 -export([new/2, interpret/1]). 4 -constructor([new/2]). 5 6 attributes. 7 8 LeftOperand; 9 RightOperand methods new(left, Right) -> self::leftoperand = Left, 15 self::rightoperand = Right interpret(variables) -> 18 Left = self::leftoperand, 19 Right = self::rightoperand, 20 Right::interpret(Variables) + 21 Left::interpret(Variables). Código 5.4.2: Classe Plus em ooerlang em ooerlang é utilizado um dicionário que funciona similarmente a uma tabela hash. Também é possivel verificar que o método interpret(), implementado na classe Plus, é modelado utilizando-se de recursão, ou seja, ele se chama novamente para o operador esquerdo e direito, com o detalhe de que o valor retornado é a operação de soma entre as chamadas deste método para ambos os operadores. Isto é feito desta forma pois um operador pode tanto ser uma variável como uma outra operação. Neste ponto que verificase o uso de uma árvore sintática para estruturar a sentença. A classe Minus também é utilizada de forma recursiva na implementação do método interpret(). A razão é a mesma pela qual isto é realizado na classe Plus. Já nas classes Variable e Number isto é diferente. Na classe Variable o método interpret() é utilizado apenas para recuperar o valor de uma variável. Na classe Number, este método apenas retorna o valor numérico da classe. A classe Evaluator realiza a construção da árvore sintática da expressão de entrada. Os códigos e mostram a implementação da classe Evaluator em Java e ooerlang, respectivamente. Nas implementações mostradas em e 5.4.4, foi dado ênfase apenas no método principal, evaluator(). Este método recebe como entrada a expressão a ser calculada. Em seguida cada token da expressão é lido e é armazenado em uma estrutura de pilha. Quando

158 Padrão Interpreter public class Evaluator implements Expression { 2 private Expression syntaxtree; 3 Stack<Expression> expressionstack = new Stack<Expression>(); 4 5 public Evaluator(String expression) { 6 for (String token : expression.split(" ")) { 7 if (token.equals("+")) { 8 Expression subexpression = 9 new Plus(expressionStack.pop(), 10 expressionstack.pop()); 11 expressionstack.push(subexpression); 12 } else if (token.equals("-")) { 13 Expression right = expressionstack.pop(); 14 Expression left = expressionstack.pop(); Expression subexpression = new Minus(left, right); 17 expressionstack.push(subexpression); 18 } else 19 expressionstack.push(new Variable(token)); 20 } 21 syntaxtree = expressionstack.pop(); 22 } Código 5.4.3: Classe Evaluator em Java um token representando uma soma é encontrado, são retirados os dois elementos do topo da pilha e com eles é criada uma nova regra para calcular a soma, representado por apenas um objeto do tipo Plus. Este objeto é inserido na pilha e a leitura da expressão continua. Ao ser encontrado um token que represente uma subtração, é realizado um procedimento semelhante ao utilizado quando se encontra um token do tipo soma. Dessa forma, a pilha vai sendo estruturada e no final vai haver apenas um objeto cujos atributos são outros objetos e/ou valores numéricos. Desta forma é que a árvore sintática vai sendo construída. E é por esse motivo que, quando uma sentença que já possui sua árvore sintática construída é interpretada, o método interpret() é utilizado recursivamente. Existem objetos sendo atributos de outros objetos. Os objetos do tipo soma (Plus) e subtração (Minus) possuem necessariamente dois objetos filhos, que são, respectivamente, seus dois atributos. Já o objeto Variable possui apenas um filho, que é um objeto do tipo Number. O objeto do tipo Number então armazena o valor numérico referente à variável do objeto pai. É importante notar que, a gramática para este exemplo, requer uma notação do tipo pós-fixada, representada por valores numéricos seguidos pelo operador dos mesmos.

159 Padrão Interpreter class(evaluator). 2 -implements(expression). 3 -export([new/1, interpret/1]). 4 -constructor([new/1]). 5 6 attributes. 7 8 SyntaxTree; 9 ExpressionStack methods new(expression) -> self::expressionstack = [], 15 aux_evaluator(expression), 16 self::syntaxtree = aux_pop() aux_evaluator([]) -> ok; 19 aux_evaluator(expression) -> 20 Token = lists:nth(1, Expression), 21 RestExpression = lists:nthtail(1, Expression), 22 if (Token == 32) -> aux_evaluator(restexpression); 25 (Token == 43) -> 26 SubExpression = plus::new(aux_pop(), aux_pop()), 27 aux_push(subexpression), 28 aux_evaluator(restexpression); 29 (Token == 45) -> 30 Right = aux_pop(), 31 Left = aux_pop(), 32 SubExpression = minus::new(left, Right), aux_push(subexpression), aux_evaluator(restexpression); 35 true -> 36 Token2 = aux_integer_to_char(token), 37 aux_push(variable::new(token2)), 38 aux_evaluator(restexpression) 39 end. Código 5.4.4: Classe Evaluator em ooerlang A classe principal deste exemplo chama-se InterpreterExample e é utilizada para testar o cálculo de uma expressão escrita na forma pós-fixada, com variáveis as quais são atribuídos valores numéricos. Os códigos mostrados em e mostram, nesta ordem, as implementações em Java e ooerlang da classe principal IntepreterExample, onde é possivel testar o funcionamento da modelagem e analisar o resultado obtido. No método principal (main) da classe InterpreterExample, inicialmente é declarada a expressão a ser interpretada e calculada. Em seguida, é instanciado um objeto da classe

160 Padrão Interpreter public class InterpreterExample { 2 public static void main(string[] args) { 3 String expression = "w x z - +"; 4 Evaluator sentence = new Evaluator(expression); 5 Map<String, Expression> variables = 6 new HashMap<String, Expression>(); 7 variables.put("w", new Number(5)); 8 variables.put("x", new Number(10)); 9 variables.put("z", new Number(42)); 10 int result = sentence.interpret(variables); 11 System.out.println("Result of sentence is: " + result); 12 } 13 } Código 5.4.5: Classe principal InterpreterExample em Java 1 -class(interpreterexample). 2 -export([main/0]). 3 4 class_methods. 5 6 main() -> 7 Expression = "w x z - +", 8 Sentence = evaluator::new(expression), 9 Variables = orddict:new(), Variables2 = orddict:store(w, number::new(5), Variables), 12 Variables3 = orddict:store(x, number::new(10), Variables2), 13 Variables4 = orddict:store(z, number::new(42), Variables3), Result = Sentence::interpret(Variables4), 16 io:format("result of sentence is: ~p~n", [Result]). Código 5.4.6: Classe principal InterpreterExample em ooerlang Evaluator, com o objetivo de receber a expressão inicial e analisar token a token dessa expressão, criando assim a árvore sintática dessa expressão. Se a sintaxe da gramática estiver correta na expressão, o resultado final do tratamento com a classe Evaluator vai ser apenas um objeto que irá possuir dentro de si (em seus atributos) todos os outros objetos para cada regra da gramática. Isto é realizado de forma recursiva. Para que a expressão utilizada possa ser calculada, é necessário que as variáveis possuam valores numéricos. Então, após ser criada a árvore sintática da expressão, é criada a tabela de valores para cada uma das variáveis presentes na expressão. Dessa forma, quando a árvore sintática da expressão é interpretada, cada variável vai poder ser substituída por seu respectivo valor numérico.

161 Padrão Interpreter 141 Após a criação da expressão, estruturação da árvore sintática da mesma expressão e definição dos valores numéricos para cada variável presente na expressão, é utilizado o método interpret(), que recebe como parâmetro de entrada o objeto-pai resultante da utilização do construtor da classe Evaluator, responsável por criar a árvore sintática. O método interpret() funciona recursivamente, para todos os objetos que estiverem presentes nos atributos de outros objetos, finalizando quando encontram os valores numéricos das variáveis. As figuras 5.8 e 5.9 mostram a execução em Java e ooerlang desta classe. Figura 5.8: Execução do exemplo para o padrão Interpreter em Java. A expressão utilizada para testar o funcionamento deste exemplo é a seguinte: w x z - +. Ou seja, ao ler esta expressão, as variáveis w, x e z são armazenadas na pilha. Ao ler o token -, os valores z e x são desempilhados e é criado um objeto do tipo x - z e este objeto é inserido na pilha. Em seguida é lido o token + e são novamente retirados dois elementos da pilha, x - z e w. Assim cria-se o objeto-pai do tipo soma representado por

162 Padrão Interpreter 142 Figura 5.9: Execução do exemplo para o padrão Interpreter em ooerlang. w + ( x - z ). Com a atribuição de valores para cada variável desta expressão, é possível calcular o resultado final e mostrá-lo ao usuário. A utilização de gramáticas para resolução de problemas gerais e para criação de linguagens simples, com poucas regras é o principal foco na implementação do padrão Interpreter na modelagem de um sistema. Verifica-se que, tanto em Java quanto em ooerlang, o exemplo estudado, que se utiliza dos conceitos do padrão de projetos Interpreter mostrou funcionar de forma semelhante. Assim, pode-se observar que a extensão ooerlang oferece suporte necessário para utilização deste padrão de projeto. Ao analisar a utilização e as características do padrão de projetos Interpreter, observase que, independente da gramática modelada, é fácil realizar modificações, assim como extensões. É possível realizar isto por meio de heranças, da mesma forma como novas expressões podem ser obtidas incrementando-se as já existentes. Em contrapartida, quando a gramática torna-se extensa demais, a manutenção do sistema torna-se mais complexa. Isto ocorre pois para cada nova regra de uma gramática, deve existir uma nova classe. Quando uma gramática é muito complexa, é mais apropriado utilizar outras técnicas, como geradores de parser e compiladores [Gamma et al., 1994].

163 Padrão Iterator Padrão Iterator O padrão de projetos Iterator, de acordo com sua definição, possui o objetivo de: Prover uma maneira de acessar os elementos de um objeto agregado sequencialmente sem expor sua representação interna [Gamma et al., 1994]. Este padrão visa uma melhor forma de interação com um conjunto de objetos, geralmente dispostos em um arranjo, sem que o usuário precise saber de que forma esses objetos são armazenados. Desta forma, se por acaso vários arranjos de objetos são estruturados de forma diferente, o usuário tem a impressão de que o acesso a esses objetos é semelhante. A utilização do padrão de projetos Iterator é recomendada em situações onde seja necessário acessar objetos agregados sem que a estrutura interna dos mesmos fique exposta ao usuário. De uma forma geral, este padrão é utilizado para suportar múltiplas formas na qual seja possível percorrer objetos agregados. Uma das situações em que isto pode ser utilizado é quando, por exemplo, tem-se diferentes estruturas de objetos agregados e necessita-se de uma interface uniforme para percorrer essas diferentes estruturas. Assim, para o usuário, não haverá diferenças entre as estruturas de objetos agregados Exemplo utilizado para este padrão Para ilustrar a utilização do padrão de projetos Iterator, é utilizado um exemplo retirado de [Freeman et al., 2004], em que existe o seguinte cenário: Duas lojas de comida pretendem fusionar-se, criando apenas uma loja com o cardápio de ambas. Uma loja vende apenas refeições do café da manhã e chama-se Pancake House e a outra está focada em vender refeições para o almoço e jantar, e chama-se Diner House. Cada uma das duas lojas de comida possui seu próprio cardápio. Ambos os restaurantes possuem um sistema que gerencia os produtos, inclusive seu cardápio. Cada uma utiliza uma classe para armazenar os tipos de pratos próprios. O restaurante de café da manhã possui a classe PancakeHouseMenu e o restaurante de almoços e jantares possui a classe DinerHouseMenu. Porém a estrutura na qual os dois restaurantes armazenam seus produtos é diferente. O restaurante Pancake House armazena seus produtos em uma estrutura chamada ArrayList (uma lista em Java que pode ser incrementada), e o restaurante Diner House armazena em um Array (lista com tamanho definido).

164 Padrão Iterator 144 Dessa forma, as estruturas que armazenam os cardápios de ambos os restaurantes são distintas e, por consequência, o acesso aos elementos de cada um dos cardápios também é distinto. Portanto, para que os restaurantes possam se unir, e para que haja facilidade no acesso dos ítens de ambos os cardápios, é necessário criar uma interface única que possa percorrer ambos os menus sem dificuldade. Para que esta interface de acesso facilitado possa ser utilizada, é necessário aplicar o padrão Iterator neste cenário. Ao utilizar o padrão Iterator, é necessário, criar uma classe de interação para ambos os cardápios. Dessa forma, criaram-se as classes DinerMenuIterator e PancakeHouseMenuIterator. Ambas as classes implementam a interface Iterator. E esta interface possui apenas dois métodos, um para verificar se ainda existe ítem e o outro para acessar o ítem seguinte do cardápio. Cada uma das classes menu implementa uma interface chamada Menu e foi utilizada uma classe chamada Waiter para servir de acesso entre os cardápios e suas classes Iterator. A figura 5.10 mostra um diagrama de classes simplificado deste cenário. As classes sobrepostas possuem implementação similar às classes que as sobrepõem. Cada classe do tipo Iterator trabalha com a estrutura específica dos cardápios. Para o usuário final, a impressão vai ser a de que os ítens estão armazenados em uma estrutura similar e que são acessados da mesma forma. O padrão Iterator permite que diferentes estruturas com objetos agregados possam ser acessadas de forma semelhante apesar de, internamente, possuírem formas de acesso distintas Comparação das implementações em Java e ooerlang A classe MenuItem, também mostrada na figura 5.10, refere-se aos ítens que são armazenados no cardápio do restaurante Diner House, ou seja, em uma instância da classe DinerMenu. Essa é outra diferença em relação à classe PancakeHouseMenu, que armazena os ítens sem instanciar objetos de nenhuma outra classe, pois utiliza uma estrutura chamada Arraylist em Java. Em e são mostrados detalhes principais dos códigos em Java e ooerlang da classe DinerMenu. Conforme pode ser observado, a classe DinerMenu armazena seus ítens (tipos de comida) em uma arranjo que possui, como característica principal, uma quantidade limitada de elementos. Outro ponto importante a ser observado é que todos os elementos presentes

165 Padrão Iterator 145 Figura 5.10: Diagrama de classes do exemplo para o padrão Iterator. na lista de objetos são instâncias da classe MenuItem. Em ooerlang a quantidade de ítens presentes na lista também é limitada e é controlada (assim como em Java) pelo atributo max itens, representando a quantidade máxima de ítens no cardápio deste restaurante. Ao verificar a implementação da classe PancakeHouseMenu, observa-se que outra estrutura foi utilizada para armazenar os ítens. É uma estrutura de arranjo, mas que não precisa necessariamente de instâncias de outra classe para que armazene os objetos do cardápio. Percebe-se, assim, que o arranjo utilizado em PancakeHouseMenu é do tipo ArrayList. Assim este arranjo não tem inicialmente uma quantidade limitada de elementos a ser inserida. Os códigos mostrados em e apresentam os principais detalhes da implementação da classe PancakeHouseMenu em Java e ooerlang.

166 Padrão Iterator public class DinerMenu implements Menu { 2 static final int MAX_ITEMS = 6; 3 int numberofitems = 0; 4 MenuItem[] menuitems; 5 6 public DinerMenu() { 7 menuitems = new MenuItem[MAX_ITEMS]; 8 9 additem("vegetarian BLT", 10 "(Fakin ) Bacon with lettuce & tomato on whole wheat", 11 true, 2.99); 12 additem("blt", "Bacon with lettuce & tomato on whole wheat", false, 2.99); 15 //outros itens } public Iterator createiterator() { 19 return new DinerMenuIterator(menuItems); 20 } 21 } Código 5.5.1: Classe DinerMenu em Java Verifica-se que, diferentemente das implementações em Java das classes DinerMenu e PancakeHouseMenu, as implementações em ooerlang utilizam ambas a mesma estrutura de armazenamento dos ítens do cardápio. E essa estrutura é uma lista simples, que é largamente utilizada em funções do Erlang. Mas os dois cardápios não são semelhantes em ooerlang por dois motivos: O primeiro é que as listas possuem limites distintos de tamanho e o segundo é que uma lista armazena instâncias de outra classe MenuItem e a outra lista insere os elementos diretamente na lista sem instanciar outra classe. Um ponto importante a ser observado nas implementações das classes DinerMenu e PancakeHouseMenu é a utilização do método createiterator(). Neste método é realizada a instância do objeto que irá interagir com todos os ítens dos referidos cardápios. Estes objetos levam em consideração a estrutura na qual os ítens do cardápio estão armazenadas, possibilitando acessar sequencialmente os referidos ítens. Os códigos mostrados em e apresentam as implementações em Java e ooerlang da classe DinerMenuIterator. A implementação em Java da classe DinerMenuIterator mostra que, o acesso aos ítens é feito diretamente por meio da indexação da posição de cada ítem. Sempre que se deseja verificar se existe um novo ítem, deve-se avaliar para saber se já chegou-se ao número máximo de ítens permitido pela classe DinerMenu. Assim consegue-se implementar, em

167 Padrão Iterator class(dinermenu). 2 -implements(menu). 3 -export([new/0, add_item/4, get_menu_items/0, create_iterator/0]). 4 -constructor([new/0]). 5 6 attributes. 7 8 MaxItems; 9 NumberOfItems; 10 MenuItems methods new() -> 15 self::menuitems = [], 16 add_item("vegetarian BLT", 17 "(Fakin ) Bacon with lettuce & tomato on whole wheat", 18 true, 2.99), 19 add_item("blt", 20 "Bacon with lettuce & tomato on whole wheat", 21 false, 2.99). 22 %outros itens create_iterator() -> 25 NewIterator = dinermenuiterator::new(self::menuitems), 26 NewIterator. Código 5.5.2: Classe DinerMenu em ooerlang DinerMenuIterator os dois métodos principais para que seja possível percorrer os ítens do cardápio do restaurante: next(), para acessar o elemento seguinte ao atual e hasnext() para verificar se ainda existem elementos não visitados. Pode ser verificado que, na implementação da classe DinerMenuIterator, tanto em Java quanto em ooerlang, cada elemento pertencente ao cardápio de uma instância da classe DinerMenu é um objeto da classe MenuItem. Isto não é o mesmo que ocorre na implementação da classe PancakeHouseMenu, onde cada elemento do cardápio é inserido diretamente em um ArrayList na implementação em Java. Em ooerlang a inserção dos elementos ocorre em uma lista semelhante à implementada no código mostrado em 5.5.2, com a diferença de que não é utilizada a classe MenuItem para instanciar os objetos. Ambas as classes DinerMenuIterator e PancakeHouseMenuIterator são utilizadas para percorrer todos os elementos pertencentes às instâncias das respectivas classes DinerMenu e PancakeHouseMenu. A interface Iterator é a implementada pelas classes responsáveis pelo acesso dos respectivos elementos. A classe que se utiliza da interface Iterator é a

168 Padrão Iterator public class PancakeHouseMenu implements Menu { 2 ArrayList menuitems; 3 4 public PancakeHouseMenu() { 5 menuitems = new ArrayList(); 6 7 additem("k&b s Pancake Breakfast", 8 "Pancakes with scrambled eggs, and toast", 9 true, ); additem("regular Pancake Breakfast", "Pancakes with fried eggs, sausage", false, ); } public Iterator createiterator() { 20 return new PancakeHouseMenuIterator(menuItems); 21 } 22 } Código 5.5.3: Classe PancakeHouseMenu em Java 1 -class(pancakehousemenu). 2 -implements(menu). 3 -export([new/0, add_item/4, get_menu_items/0, create_iterator/0, to_string/0]). 4 -constructor([new/0]). 5 6 attributes. 7 8 MenuItems methods new() -> 13 self::menuitems = [], 14 add_item("k & B s Pancake Breakfast", "Pancakes with scrambled eggs, and toast", true, 2.99), 17 add_item("regular Pancake Breakfast", 18 "Pancakes with fried eggs, sausage", 19 false, 2.99). 20 %outros itens create_iterator() -> 23 NewIterator = pancakehousemenuiterator::new(self::menuitems), 24 NewIterator. Código 5.5.4: Classe PancakeHouseMenu em ooerlang

169 Padrão Iterator public class DinerMenuIterator implements Iterator { 2 MenuItem[] items; 3 int position = 0; 4 5 public DinerMenuIterator(MenuItem[] items) { 6 this.items = items; 7 } 8 9 public Object next() { 10 MenuItem menuitem = items[position]; 11 position = position + 1; 12 return menuitem; 13 } public boolean hasnext() { 16 if (position >= items.length items[position] == null) { 17 return false; 18 } else { 19 return true; 20 } 21 } 22 } Código 5.5.5: Classe DinerMenuIterator em Java classe Waitress, sendo de sua responsabilidade acessar ambos os cardápios utilizando-se da mesma interface. Os códigos mostrados em e apresentam, respectivamente em Java e ooerlang, os detalhes principais da implementação da classe Waitress. A classe Waitress possui dois atributos, pancakehousemenu e dinermenu. Estes atributos recebem as instâncias das classes PancakeHouseMenuIterator e DinerMenuIterator respectivamente. Dessa forma é possivel manusear os dois cardápios, e utilizar-se da mesma interface para percorrer os ítens dos mesmos. Além de um construtor, a classe Waitress possui também o método printmenu(), no qual os atributos da classe são utilizados para que seja possível percorrer e imprimir todos os elementos de ambos os cardápios. A classe principal deste exemplo chama-se MenuTestDrive. Conforme é mostrado nos códigos e que representam as implementações em Java e ooerlang, nesta ordem, da classe principal, são testadas as duas classes que implementam a interface Iterator. Para isto, instanciam-se dois objetos, referentes às classes PancakeHouseMenu e DinerMenu. Em seguida estes objetos são passados por parâmetro na instanciação do objeto da classe Waitress, criando assim os respectivos objetos de interação. Conforme mostrado nas implementações da classe MenuTestDrive, ao ser instanciado

170 Padrão Iterator class(dinermenuiterator). 2 -implements(iterator). 3 -export([new/1, next/0, has_next/0]). 4 -constructor([new/1]). 5 6 attributes. 7 8 Items; 9 Position methods new(items) -> 14 self::items = Items next() -> 17 MenuItem = lists:nth(self::position, self::items), 18 self::position = self::position + 1, 19 MenuItem has_next() -> 22 Pos = self::position, Itm = self::items, if 25 (Pos >= length(itm)) -> 26 false; 27 true -> 28 true 29 end. Código 5.5.6: Classe DinerMenuIterator em ooerlang um objeto da classe Waitress, os parâmetros recebidos na instanciação são instâncias das classes que possuem os diferentes cardápios de produtos. Quando a instância da classe Waitress invoca o método printmenu(), na classe Waitress, internamente, são criadas as instâncias das classes que implementam a interface Iterator e que são responsáveis por percorrer ambas as listas de produtos. Assim, com a chamada de apenas um método foi possível verificar os elementos de duas diferentes agregações. As figuras mostradas em 5.11 e 5.12 mostram a execução do exemplo que implementa o padrão de projetos Iterator em Java e ooerlang, respectivamente. Verifica-se que, ambas as implementações utilizaram os mesmos ítens de cardápio, para que a comparação das execuções possa demonstrar semelhança nas implementações realizadas em Java e ooerlang. São percorridas as listas de produtos dos cardápios das classe PancakeHouseMenu e DinerMenu, nesta sequência, imprimindo cada ítem de cada cardápio.

171 Padrão Iterator public class Waitress { 2 PancakeHouseMenu pancakehousemenu; 3 DinerMenu dinermenu; 4 5 public Waitress(PancakeHouseMenu pancakehousemenu, DinerMenu dinermenu) { 6 this.pancakehousemenu = pancakehousemenu; 7 this.dinermenu = dinermenu; 8 } 9 10 public void printmenu() { 11 Iterator pancakeiterator = pancakehousemenu.createiterator(); 12 Iterator dineriterator = dinermenu.createiterator(); System.out.println("MENU\n----\nBREAKFAST"); 15 printmenu(pancakeiterator); 16 System.out.println("\nLUNCH"); 17 printmenu(dineriterator); 18 } private void printmenu(iterator iterator) { 21 while (iterator.hasnext()) { 22 MenuItem menuitem = (MenuItem)iterator.next(); System.out.print(menuItem.getName() + ", "); System.out.print(menuItem.getPrice() + " -- "); 25 System.out.println(menuItem.getDescription()); 26 } 27 } Código 5.5.7: Classe Waitress em Java No exemplo mostrado, o padrão de projetos Iterator é utilizado no caso específico em que há a necessidade de acesso a diferentes conjuntos de objetos (agregações) utilizando-se de uma mesma interface. Desta forma, para o usuário, os acessos realizados nos diferentes conjuntos de objetos aparentam ter sido executados de forma semelhante por terem utilizado uma interface em comum, entretanto, estes objetos estão armazenados em diferentes estruturas, e seu acesso é, logicamente, diferente. Para que seja possível utilizar uma mesma interface com o objetivo de acessar conjuntos de objetos diferentes de forma semelhante, são modeladas classes que implementam esta interface e, internamente, tratam do acesso específico de cada estrutura de armazenamento. O usuário, ao se utilizar de um sistema que possui esta modelagem não irá precisar se preocupar com a estrutura interna de cada agregação de objetos a ser percorrida pelo sistema. Este exemplo ilustra uma situação em que é necessário associar dois sistemas seme-

172 Padrão Iterator class(waitress). 2 -export([new/2, print_menu/0, print_menu/1]). 3 -export([print_vegetarian_menu/0, is_item_vegetarian/1]). 4 -export([print_vegetarian_menu/1, is_vegetarian/2]). 5 -constructor([new/2]). 6 7 attributes. 8 9 PancakeHouseMenu; 10 DinerMenu methods new(pancakehousemenu,dinermenu) -> 15 self::pancakehousemenu = PancakeHouseMenu, 16 self::dinermenu = DinerMenu print_menu() -> 19 Pancake = self::pancakehousemenu, 20 Diner = self::dinermenu, PancakeIterator = Pancake::create_iterator(), 23 DinerIterator = Diner::create_iterator(), io:format("menu~n----~nbreakfast~n"), 26 print_the_menu(pancake::menuitems), 27 io:format("~nlunch~n"), 28 print_the_menu(diner::menuitems). Código 5.5.8: Classe Waitress em ooerlang 1 public class MenuTestDrive { 2 public static void main(string args[]) { 3 PancakeHouseMenu pancakehousemenu = new PancakeHouseMenu(); 4 DinerMenu dinermenu = new DinerMenu(); 5 6 Waitress waitress = new Waitress(pancakeHouseMenu, dinermenu); 7 8 waitress.printmenu(); 9 } Código 5.5.9: Classe principal MenuTestDrive em Java lhantes porém com estruturas diferentes em um único sistema. Neste caso, a utilização do padrão Iterator tornou possivel a referida associação sem que fosse necessário modificar as estruturas que armazenam os ítens de cardápio de cada sistema. Obtém-se, dessa forma, uma solução que não produz muitos impactos na modelagem como um todo e que facilita a manutenção e extensão do referido sistema.

173 Padrão Iterator class(menutestdrive). 2 -export([main/0]). 3 4 class_methods. 5 6 main() -> 7 PancakeHouseMenu = pancakehousemenu::new(), 8 DinerMenu = dinermenu::new(), 9 10 io:format("pancakehousemenu: ~p~n", [PancakeHouseMenu]), 11 io:format("dinermenu: ~p~n", [DinerMenu]), 12 Waitress = waitress::new(pancakehousemenu, DinerMenu), Waitress::print_menu(). Código : Classe principal MenuTestDrive em ooerlang Figura 5.11: Execução do exemplo para o padrão Iterator em Java. Ao se utilizar do padrão de projetos Iterator, percebe-se que uma das características é a de que este padrão suporta variações no percorrimento de uma agregação, sendo possível

Programação Orientada a Objetos. Padrões de Criação

Programação Orientada a Objetos. Padrões de Criação Programação Orientada a Objetos Padrões de Criação Cristiano Lehrer, M.Sc. Objetivos Apresentar cada um dos 23 padrões clássicos descrevendo: O problema que solucionam. A solução. Diagramas UML (Unified

Leia mais

Padrões de Projeto. Prof. Jefersson Alex dos Santos (jefersson@dcc.ufmg.br) http://www.dcc.ufmg.br/~jefersson

Padrões de Projeto. Prof. Jefersson Alex dos Santos (jefersson@dcc.ufmg.br) http://www.dcc.ufmg.br/~jefersson Padrões de Projeto Prof. Jefersson Alex dos Santos (jefersson@dcc.ufmg.br) http://www.dcc.ufmg.br/~jefersson Apresentação Conceitos Definição Ponto de vista prático História Padrões de Projeto Conhecidos

Leia mais

Curso - Padrões de Projeto Módulo 1: Introdução

Curso - Padrões de Projeto Módulo 1: Introdução Curso - Padrões de Projeto Módulo 1: Introdução Vítor E. Silva Souza vitorsouza@gmail.com http://www.javablogs.com.br/page/engenho http://esjug.dev.java.net Sobre o Instrutor Formação: Java: Graduação

Leia mais

J930. Padrões. Projeto. Introdução. argonavis.com.br. Helder da Rocha (helder@acm.org)

J930. Padrões. Projeto. Introdução. argonavis.com.br. Helder da Rocha (helder@acm.org) Padrões de J930 Projeto Introdução Helder da Rocha (helder@acm.org) argonavis.com.br O que é um padrão? Maneira testada ou documentada de alcançar um objetivo qualquer Padrões são comuns em várias áreas

Leia mais

PADRÕES DE SOFTWARE. Jerffeson Teixeira de Souza, Ph.D. Tarciane de Castro Andrade. Grupo de Padrões de Software da UECE (GPS.

PADRÕES DE SOFTWARE. Jerffeson Teixeira de Souza, Ph.D. Tarciane de Castro Andrade. Grupo de Padrões de Software da UECE (GPS. PADRÕES DE SOFTWARE 1 Jerffeson Teixeira de Souza, Ph.D. Tarciane de Castro Andrade Grupo de Padrões de Software da UECE (GPS.UECE) Julho-2009 CONTEÚDO Introdução aos Padrões de Software O quê são padrões?

Leia mais

UNIVERSIDADE FEDERAL DO PARANÁ UFPR Bacharelado em Ciência da Computação

UNIVERSIDADE FEDERAL DO PARANÁ UFPR Bacharelado em Ciência da Computação SOFT DISCIPLINA: Engenharia de Software AULA NÚMERO: 10 DATA: / / PROFESSOR: Andrey APRESENTAÇÃO O objetivo desta aula é apresentar e discutir os conceitos de coesão e acoplamento. DESENVOLVIMENTO Projetar

Leia mais

1Introdução Helder da Rocha (helder@acm.org)

1Introdução Helder da Rocha (helder@acm.org) J930 Padrões Projeto de 1Introdução Helder da Rocha (helder@acm.org) argonavis.com.br O que é um padrão? Maneira testada ou documentada de alcançar um objetivo qualquer Padrões são comuns em várias áreas

Leia mais

UML Aspectos de projetos em Diagramas de classes

UML Aspectos de projetos em Diagramas de classes UML Aspectos de projetos em Diagramas de classes Após ser definido o contexto da aplicação a ser gerada. Devemos pensar em detalhar o Diagrama de Classes com informações visando uma implementação Orientada

Leia mais

Programação Avançada. Padrões de Projeto de Software. Fonte: Oswaldo B. Peres e K19 Treinamentos

Programação Avançada. Padrões de Projeto de Software. Fonte: Oswaldo B. Peres e K19 Treinamentos Programação Avançada Padrões de Projeto de Software 1 Fonte: Oswaldo B. Peres e K19 Treinamentos Introdução Projetar software OO reusável e de boa qualidade é uma tarefa difícil; Para realizar essa tarefa

Leia mais

Testes com Design Patterns

Testes com Design Patterns Helder da Rocha (helder.darocha@gmail.com) 31 de março de 2005 71. Que padrão de design pode ser usado para permitir que uma implementação específica e uma hierarquia de abstrações possa variar independentemente?

Leia mais

PROGRAMAÇÃO AVANÇADA -CONCEITOS DE ORIENTAÇÃO A OBJETOS. Prof. Angelo Augusto Frozza, M.Sc. frozza@ifc-camboriu.edu.br

PROGRAMAÇÃO AVANÇADA -CONCEITOS DE ORIENTAÇÃO A OBJETOS. Prof. Angelo Augusto Frozza, M.Sc. frozza@ifc-camboriu.edu.br PROGRAMAÇÃO AVANÇADA -CONCEITOS DE ORIENTAÇÃO A OBJETOS Prof. Angelo Augusto Frozza, M.Sc. frozza@ifc-camboriu.edu.br ROTEIRO 1. Conceitos de Orientação a Objetos Introdução O paradigma da POO Classes

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 de Projeto em Desenvolvimento Web SCC 266. Prof. Renata Pontin M. Fortes renata@icmc.usp.br PAE: Willian Watanabe (watinha@gmail.

Padrões de Projeto em Desenvolvimento Web SCC 266. Prof. Renata Pontin M. Fortes renata@icmc.usp.br PAE: Willian Watanabe (watinha@gmail. Padrões de Projeto em Desenvolvimento Web SCC 266 Prof. Renata Pontin M. Fortes renata@icmc.usp.br PAE: Willian Watanabe (watinha@gmail.com) 2.semestre 2010 Instituto de Ciências Matemáticas e de Computação

Leia mais

Conteúdo. Disciplina: INF 02810 Engenharia de Software. Monalessa Perini Barcellos. Centro Tecnológico. Universidade Federal do Espírito Santo

Conteúdo. Disciplina: INF 02810 Engenharia de Software. Monalessa Perini Barcellos. Centro Tecnológico. Universidade Federal do Espírito Santo Universidade Federal do Espírito Santo Centro Tecnológico Departamento de Informática Disciplina: INF 02810 Prof.: (monalessa@inf.ufes.br) Conteúdo 1. Introdução 2. Processo de Software 3. Gerência de

Leia mais

Orientação a Objetos

Orientação a Objetos 1. Domínio e Aplicação Orientação a Objetos Um domínio é composto pelas entidades, informações e processos relacionados a um determinado contexto. Uma aplicação pode ser desenvolvida para automatizar ou

Leia mais

Diagrama de Classes. Um diagrama de classes descreve a visão estática do sistema em termos de classes e relacionamentos entre as classes.

Diagrama de Classes. Um diagrama de classes descreve a visão estática do sistema em termos de classes e relacionamentos entre as classes. 1 Diagrama de Classes Um diagrama de classes descreve a visão estática do sistema em termos de classes e relacionamentos entre as classes. Um dos objetivos do diagrama de classes é definir a base para

Leia mais

Padrões GoF. Leonardo Gresta Paulino Murta leomurta@ic.uff.br

Padrões GoF. Leonardo Gresta Paulino Murta leomurta@ic.uff.br Padrões GoF Leonardo Gresta Paulino Murta leomurta@ic.uff.br Agenda Introdução Padrões de Criação Padrões de Estrutura Padrões de comportamento Leonardo Murta Padrões GoF 2 Introdução Os padrões GoF (Gamma

Leia mais

Análise e Desenvolvimento de Sistemas ADS Programação Orientada a Obejeto POO 3º Semestre AULA 03 - INTRODUÇÃO À PROGRAMAÇÃO ORIENTADA A OBJETO (POO)

Análise e Desenvolvimento de Sistemas ADS Programação Orientada a Obejeto POO 3º Semestre AULA 03 - INTRODUÇÃO À PROGRAMAÇÃO ORIENTADA A OBJETO (POO) Análise e Desenvolvimento de Sistemas ADS Programação Orientada a Obejeto POO 3º Semestre AULA 03 - INTRODUÇÃO À PROGRAMAÇÃO ORIENTADA A OBJETO (POO) Parte: 1 Prof. Cristóvão Cunha Objetivos de aprendizagem

Leia mais

2 Diagrama de Caso de Uso

2 Diagrama de Caso de Uso Unified Modeling Language (UML) Universidade Federal do Maranhão UFMA Pós Graduação de Engenharia de Eletricidade Grupo de Computação Assunto: Diagrama de Caso de Uso (Use Case) Autoria:Aristófanes Corrêa

Leia mais

Prof.ª Esp. Talita Pagani

Prof.ª Esp. Talita Pagani Especialização em Engenharia de Software Prof.ª Esp. Talita Pagani talita.cpb@gmail.com @talitapagani 21/02/2014 Design Patterns Aula 1 Prof.ª Esp. Talita Pagani 1 Informações gerais 1. Definição de Design

Leia mais

ATRIBUTOS PRIVADOS 6. ENCAPSULAMENTO MÉTODOS PRIVADOS MÉTODOS PRIVADOS

ATRIBUTOS PRIVADOS 6. ENCAPSULAMENTO MÉTODOS PRIVADOS MÉTODOS PRIVADOS ATRIBUTOS PRIVADOS Podemos usar o modificador private, para tornar um atributo privado, obtendo um controle centralizado Definimos métodos para implementar todas as lógicas que utilizam ou modificam o

Leia mais

Prototype, um Design Patterns de Criação

Prototype, um Design Patterns de Criação Prototype, um Design Patterns de Criação José Anízio Pantoja Maia Este artigo tem como finalidade compreender o funcionamento do padrão de projeto prototype, serão abordados os participantes que compõe

Leia mais

2 Engenharia de Software

2 Engenharia de Software 20 2 Engenharia de Software 2.1 Design de Sistemas Orientados a Objetos Os Sistemas Orientados a Objetos não são mais novidade hoje em dia já estando há muitos anos no mercado. A orientação a objetos permite

Leia mais

Para construção dos modelos físicos, será estudado o modelo Relacional como originalmente proposto por Codd.

Para construção dos modelos físicos, será estudado o modelo Relacional como originalmente proposto por Codd. Apresentação Este curso tem como objetivo, oferecer uma noção geral sobre a construção de sistemas de banco de dados. Para isto, é necessário estudar modelos para a construção de projetos lógicos de bancos

Leia mais

Design Pattern Implementation in Java and AspectJ

Design Pattern Implementation in Java and AspectJ Design Pattern Implementation in Java and AspectJ Jan Hannemann Gregor Kiczales In Proceedings of 2002 ACM SIGPLAN conference on OOPSLA. NY, USA. Introdução 2 Introdução 3 Introdução 4 Introdução 5 Introdução

Leia mais

3.1 Definições Uma classe é a descrição de um tipo de objeto.

3.1 Definições Uma classe é a descrição de um tipo de objeto. Unified Modeling Language (UML) Universidade Federal do Maranhão UFMA Pós Graduação de Engenharia de Eletricidade Grupo de Computação Assunto: Diagrama de Classes Autoria:Aristófanes Corrêa Silva Adaptação:

Leia mais

Engenharia de Software III

Engenharia de Software III Engenharia de Software III Casos de uso http://dl.dropbox.com/u/3025380/es3/aula6.pdf (flavio.ceci@unisul.br) 09/09/2010 O que são casos de uso? Um caso de uso procura documentar as ações necessárias,

Leia mais

Sumário. Uma visão mais clara da UML

Sumário. Uma visão mais clara da UML Instituto Federal de Santa Catarina Câmpus Chapecó Ensino Médio Integrado em Informática Módulo V Unidade Curricular: Engenharia de Software Professora: Lara P. Z. B. Oberderfer Uma visão mais clara da

Leia mais

ENGENHARIA DE SOFTWARE I

ENGENHARIA DE SOFTWARE I ENGENHARIA DE SOFTWARE I Prof. Cássio Huggentobler de Costa [cassio.costa@ulbra.br] Twitter: www.twitter.com/cassiocosta_ Agenda da Aula (002) Metodologias de Desenvolvimento de Softwares Métodos Ágeis

Leia mais

Engenharia de Software na Prática Hélio Engholm Jr.

Engenharia de Software na Prática Hélio Engholm Jr. Engenharia de Software na Prática Hélio Engholm Jr. Novatec Sumário Agradecimentos... 17 Sobre o autor... 18 Prefácio... 19 Capítulo 1 Desenvolvimento de software para o valor de negócios... 20 1.1 Qualidade

Leia mais

Padrões de projeto 1

Padrões de projeto 1 Padrões de projeto 1 Design Orientado Objeto Encapsulamento Herança Polimorfismo Design Patterns 2 Responsabilidades Booch e Rumbaugh Responsabilidade é um contrato ou obrigação de um tipo ou classe. Dois

Leia mais

UML - Unified Modeling Language

UML - Unified Modeling Language UML - Unified Modeling Language Casos de Uso Marcio E. F. Maia Disciplina: Engenharia de Software Professora: Rossana M. C. Andrade Curso: Ciências da Computação Universidade Federal do Ceará 24 de abril

Leia mais

Programação de Computadores - I. Profª Beatriz Profº Israel

Programação de Computadores - I. Profª Beatriz Profº Israel Programação de Computadores - I Profª Beatriz Profº Israel Ambiente de Desenvolvimento Orientação a Objetos É uma técnica de desenvolvimento de softwares que consiste em representar os elementos do mundo

Leia mais

Orientação à Objetos. Aécio Costa

Orientação à Objetos. Aécio Costa Aécio Costa O paradigma da orientação à objetos Paradigma? Um paradigma é uma forma de abordar um problema. No contexto da modelagem de um sistema de software, um paradigma tem a ver com a forma pela qual

Leia mais

Reuso com Herança a e Composiçã

Reuso com Herança a e Composiçã Java 2 Standard Edition Reuso com Herança a e Composiçã ção Helder da Rocha www.argonavis.com.br 1 Como aumentar as chances de reuso Separar as partes que podem mudar das partes que não mudam. Exemplo:

Leia mais

Programação Orientada a Objetos Herança Técnico em Informática. Prof. Marcos André Pisching, M.Sc.

Programação Orientada a Objetos Herança Técnico em Informática. Prof. Marcos André Pisching, M.Sc. Herança Técnico em Informática, M.Sc. Herança 2 Herança Reutilização de código Exemplo Banco: Um banco oferece diversos serviços que podem ser contratados individualmente pelos clientes. Quando um serviço

Leia mais

Decorator Pattern. SISMO - Sistemas e Mobilidade http://www.sismo.deinf.ufma.br. Junho de 2008. Departamento de Informática / UFMA

Decorator Pattern. SISMO - Sistemas e Mobilidade http://www.sismo.deinf.ufma.br. Junho de 2008. Departamento de Informática / UFMA Decorator Pattern SISMO - Sistemas e Mobilidade http://www.sismo.deinf.ufma.br Departamento de Informática / UFMA Junho de 2008 Revisando os conceitos Herança é poderosa mas não é flexível Comportamento

Leia mais

Prof. Marcelo Henrique dos Santos

Prof. Marcelo Henrique dos Santos ORIENTAÇÃO A OBJETOS COM PROTOTIPAÇÃO CAPÍTULO 02 CONCEITOS FUNDAMENTAIS OBJETIVOS Definiremos alguns conceitos fundamentais de forma a não deixar dúvidas básicas ou interpretações que nos coloquem em

Leia mais

Feature-Driven Development

Feature-Driven Development FDD Feature-Driven Development Descrição dos Processos Requisitos Concepção e Planejamento Mais forma que conteúdo Desenvolver um Modelo Abrangente Construir a Lista de Features Planejar por

Leia mais

Modelagemde Software Orientadaa Objetos com UML

Modelagemde Software Orientadaa Objetos com UML Modelagemde Software Orientadaa Objetos com UML André Maués Brabo Pereira Departamento de Engenharia Civil Universidade Federal Fluminense Colaborando para a disciplina CIV 2802 Sistemas Gráficos para

Leia mais

Na medida em que se cria um produto, o sistema de software, que será usado e mantido, nos aproximamos da engenharia.

Na medida em que se cria um produto, o sistema de software, que será usado e mantido, nos aproximamos da engenharia. 1 Introdução aos Sistemas de Informação 2002 Aula 4 - Desenvolvimento de software e seus paradigmas Paradigmas de Desenvolvimento de Software Pode-se considerar 3 tipos de paradigmas que norteiam a atividade

Leia mais

Modelagem OO com UML. Vítor E. Silva Souza (vitorsouza@inf.ufes.br) http://www.inf.ufes.br/ ~ vitorsouza

Modelagem OO com UML. Vítor E. Silva Souza (vitorsouza@inf.ufes.br) http://www.inf.ufes.br/ ~ vitorsouza Modelagem OO com UML Vítor E. Silva Souza (vitorsouza@inf.ufes.br) http://www.inf.ufes.br/ ~ vitorsouza Departamento de Informática Centro Tecnológico Universidade Federal do Espírito Santo Modelos Maneira

Leia mais

EXERCÍCIOS SOBRE ORIENTAÇÃO A OBJETOS

EXERCÍCIOS SOBRE ORIENTAÇÃO A OBJETOS Campus Cachoeiro de Itapemirim Curso Técnico em Informática Disciplina: Análise e Projeto de Sistemas Professor: Rafael Vargas Mesquita Este exercício deve ser manuscrito e entregue na próxima aula; Valor

Leia mais

Felipe Denis M. de Oliveira. Fonte: Alice e Carlos Rodrigo (Internet)

Felipe Denis M. de Oliveira. Fonte: Alice e Carlos Rodrigo (Internet) UML Felipe Denis M. de Oliveira Fonte: Alice e Carlos Rodrigo (Internet) 1 Programação O que é UML? Por quê UML? Benefícios Diagramas Use Case Class State Interaction Sequence Collaboration Activity Physical

Leia mais

Conceitos de Banco de Dados

Conceitos de Banco de Dados Conceitos de Banco de Dados Autor: Luiz Antonio Junior 1 INTRODUÇÃO Objetivos Introduzir conceitos básicos de Modelo de dados Introduzir conceitos básicos de Banco de dados Capacitar o aluno a construir

Leia mais

DESENVOLVENDO APLICAÇÃO UTILIZANDO JAVA SERVER FACES

DESENVOLVENDO APLICAÇÃO UTILIZANDO JAVA SERVER FACES DESENVOLVENDO APLICAÇÃO UTILIZANDO JAVA SERVER FACES Alexandre Egleilton Araújo, Jaime Willian Dias Universidade Paranaense (Unipar) Paranavaí PR Brasil araujo.ale01@gmail.com, jaime@unipar.br Resumo.

Leia mais

Tabela de Símbolos. Análise Semântica A Tabela de Símbolos. Principais Operações. Estrutura da Tabela de Símbolos. Declarações 11/6/2008

Tabela de Símbolos. Análise Semântica A Tabela de Símbolos. Principais Operações. Estrutura da Tabela de Símbolos. Declarações 11/6/2008 Tabela de Símbolos Análise Semântica A Tabela de Símbolos Fabiano Baldo Após a árvore de derivação, a tabela de símbolos é o principal atributo herdado em um compilador. É possível, mas não necessário,

Leia mais

Programação Orientada a Objetos Prof. Rone Ilídio UFSJ/CAP

Programação Orientada a Objetos Prof. Rone Ilídio UFSJ/CAP Programação Orientada a Objetos Prof. Rone Ilídio UFSJ/CAP 1) Introdução Programação Orientada a Objetos é um paradigma de programação bastante antigo. Entretanto somente nos últimos anos foi aceito realmente

Leia mais

Orientação a Objeto e UML Questões 2014 Prof. Felipe Leite

Orientação a Objeto e UML Questões 2014 Prof. Felipe Leite Orientação a Objeto e UML Questões 2014 Prof. Felipe Leite Pessoal, fiz uma coletânea das questões mais recentes de concursos públicos de TODO o Brasil de várias bancas diferentes sobre os assuntos Orientação

Leia mais

Apesar de existirem diversas implementações de MVC, em linhas gerais, o fluxo funciona geralmente da seguinte forma:

Apesar de existirem diversas implementações de MVC, em linhas gerais, o fluxo funciona geralmente da seguinte forma: 1 Introdução A utilização de frameworks como base para a construção de aplicativos tem sido adotada pelos desenvolvedores com três objetivos básicos. Primeiramente para adotar um padrão de projeto que

Leia mais

Especificação do 3º Trabalho

Especificação do 3º Trabalho Especificação do 3º Trabalho I. Introdução O objetivo deste trabalho é abordar a prática da programação orientada a objetos usando a linguagem Java envolvendo os conceitos de classe, objeto, associação,

Leia mais

TRABALHO DE DIPLOMAÇÃO Regime Modular ORIENTAÇÕES SOBRE O ROTEIRO DO PROJETO FINAL DE SISTEMAS DE INFORMAÇÕES

TRABALHO DE DIPLOMAÇÃO Regime Modular ORIENTAÇÕES SOBRE O ROTEIRO DO PROJETO FINAL DE SISTEMAS DE INFORMAÇÕES TRABALHO DE DIPLOMAÇÃO Regime Modular ORIENTAÇÕES SOBRE O ROTEIRO DO PROJETO FINAL DE SISTEMAS DE INFORMAÇÕES [Observação: O template a seguir é utilizado como roteiro para projeto de sistemas orientado

Leia mais

Análise e Projeto Orientados por Objetos

Análise e Projeto Orientados por Objetos Análise e Projeto Orientados por Objetos Apresentação da Disciplina Edirlei Soares de Lima Objetivos da Disciplina Apresentar e discutir técnicas avançadas de Análise e Projeto de

Leia mais

Governança de TI. ITIL v.2&3. parte 1

Governança de TI. ITIL v.2&3. parte 1 Governança de TI ITIL v.2&3 parte 1 Prof. Luís Fernando Garcia LUIS@GARCIA.PRO.BR ITIL 1 1 ITIL Gerenciamento de Serviços 2 2 Gerenciamento de Serviços Gerenciamento de Serviços 3 3 Gerenciamento de Serviços

Leia mais

Engenharia de Requisitos

Engenharia de Requisitos Engenharia de Requisitos Introdução a Engenharia de Requisitos Professor: Ricardo Argenton Ramos Aula 08 Slide 1 Objetivos Introduzir a noção de requisitos do sistema e o processo da engenharia de requisitos.

Leia mais

Programação Estruturada e Orientada a Objetos. Fundamentos Orientação a Objetos

Programação Estruturada e Orientada a Objetos. Fundamentos Orientação a Objetos Programação Estruturada e Orientada a Objetos Fundamentos Orientação a Objetos 2013 O que veremos hoje? Introdução aos fundamentos de Orientação a Objetos Transparências baseadas no material do Prof. Jailton

Leia mais

PROCESSO DE DESENVOLVIMENTO DE SOFTWARE. Modelos de Processo de Desenvolvimento de Software

PROCESSO DE DESENVOLVIMENTO DE SOFTWARE. Modelos de Processo de Desenvolvimento de Software PROCESSO DE DESENVOLVIMENTO DE SOFTWARE Introdução Modelos de Processo de Desenvolvimento de Software Os modelos de processos de desenvolvimento de software surgiram pela necessidade de dar resposta às

Leia mais

Wilson Moraes Góes. Novatec

Wilson Moraes Góes. Novatec Wilson Moraes Góes Novatec Copyright 2014 Novatec Editora Ltda. Todos os direitos reservados e protegidos pela Lei 9.610 de 19/02/1998. É proibida a reprodução desta obra, mesmo parcial, por qualquer processo,

Leia mais

UML: Diagrama de Casos de Uso, Diagrama de Classes

UML: Diagrama de Casos de Uso, Diagrama de Classes UML: Diagrama de Casos de Uso, Diagrama de Classes Diagrama de Casos de Uso O modelo de casos de uso visa responder a pergunta: Que usos (funcionalidades) o sistema terá? ou Para que aplicações o sistema

Leia mais

Engenharia de Software: conceitos e aplicações. Prof. Tiago Eugenio de Melo, MSc tiagodemelo@gmail.com

Engenharia de Software: conceitos e aplicações. Prof. Tiago Eugenio de Melo, MSc tiagodemelo@gmail.com Engenharia de Software: conceitos e aplicações Prof. Tiago Eugenio de Melo, MSc tiagodemelo@gmail.com 1 Objetivos da aula Apresentar os conceitos de Engenharia de Software e explicar a sua importância.

Leia mais

Aspectos técnicos do desenvolvimento baseado em componentes

Aspectos técnicos do desenvolvimento baseado em componentes Aspectos técnicos do desenvolvimento baseado em componentes Um novo processo de desenvolvimento O uso de componentes traz mudanças no processo de desenvolvimento Além de desenvolver um produto, queremos

Leia mais

Análise e Projeto de Sistemas de Informação. Andrêza Leite andreza.lba@gmail.com

Análise e Projeto de Sistemas de Informação. Andrêza Leite andreza.lba@gmail.com Análise e Projeto de Sistemas de Informação Andrêza Leite andreza.lba@gmail.com Roteiro Sistemas de Informação Ciclo de Desenvolvimento de SI Projeto Análise Estruturada Análise Orientada a Objetos Como

Leia mais

Polimorfismo. Prof. Leonardo Barreto Campos 1

Polimorfismo. Prof. Leonardo Barreto Campos 1 Polimorfismo Prof. Leonardo Barreto Campos 1 Sumário Introdução; Polimorfismo; Polimorfismo Java; Métodos Abstratos Java Classes Abstratas Java Exercício - Java Polimorfismo C++ Classe Abstrata C++; Funções

Leia mais

Pasteur Ottoni de Miranda Junior. Alguns Padrões de Projeto Gamma

Pasteur Ottoni de Miranda Junior. Alguns Padrões de Projeto Gamma Pasteur Ottoni de Miranda Junior Alguns Padrões de Projeto Gamma Padrões Gamma de Projeto(ou Gang-of-Four, gof) Os padrões gof foram publicados por Erich Gamma, Richard Helm, Ralph Johnson e John Vlissides

Leia mais

04/08/2012 MODELAGEM DE DADOS. PROF. RAFAEL DIAS RIBEIRO, M.Sc. @ribeirord MODELAGEM DE DADOS. Aula 2. Prof. Rafael Dias Ribeiro. M.Sc.

04/08/2012 MODELAGEM DE DADOS. PROF. RAFAEL DIAS RIBEIRO, M.Sc. @ribeirord MODELAGEM DE DADOS. Aula 2. Prof. Rafael Dias Ribeiro. M.Sc. MODELAGEM DE DADOS PROF. RAFAEL DIAS RIBEIRO, M.Sc. @ribeirord MODELAGEM DE DADOS Aula 2 Prof. Rafael Dias Ribeiro. M.Sc. @ribeirord 1 Objetivos: Revisão sobre Banco de Dados e SGBDs Aprender as principais

Leia mais

Engenharia de software para desenvolvimento com LabVIEW: Validação

Engenharia de software para desenvolvimento com LabVIEW: Validação Engenharia de software para desenvolvimento com LabVIEW: Orientação a Objetos, Statechart e Validação André Pereira Engenheiro de Vendas (Grande São Paulo) Alexsander Loula Coordenador Suporte Técnico

Leia mais

UM ESTUDO PARA A EVOLUÇÃO DO PHP COM A LINGUAGEM ORIENTADA A OBJETOS

UM ESTUDO PARA A EVOLUÇÃO DO PHP COM A LINGUAGEM ORIENTADA A OBJETOS UM ESTUDO PARA A EVOLUÇÃO DO PHP COM A LINGUAGEM ORIENTADA A OBJETOS Jean Henrique Zenzeluk* Sérgio Ribeiro** Resumo. Este artigo descreve os conceitos de Orientação a Objetos na linguagem de programação

Leia mais

ISO/IEC 12207: Gerência de Configuração

ISO/IEC 12207: Gerência de Configuração ISO/IEC 12207: Gerência de Configuração Durante o processo de desenvolvimento de um software, é produzida uma grande quantidade de itens de informação que podem ser alterados durante o processo Para que

Leia mais

Metodologias de Desenvolvimento de Sistemas. Analise de Sistemas I UNIPAC Rodrigo Videschi

Metodologias de Desenvolvimento de Sistemas. Analise de Sistemas I UNIPAC Rodrigo Videschi Metodologias de Desenvolvimento de Sistemas Analise de Sistemas I UNIPAC Rodrigo Videschi Histórico Uso de Metodologias Histórico Uso de Metodologias Era da Pré-Metodologia 1960-1970 Era da Metodologia

Leia mais

O CONCEITO DE TDD NO DESENVOLVIMENTO DE SOFTWARE

O CONCEITO DE TDD NO DESENVOLVIMENTO DE SOFTWARE O CONCEITO DE TDD NO DESENVOLVIMENTO DE SOFTWARE Renan Leme Nazário, Ricardo Rufino Universidade Paranaense (Unipar) Paranavaí PR - Brasil renazariorln@gmail.com, ricardo@unipar.br Resumo. Este artigo

Leia mais

Análise e Projeto Orientados por Objetos

Análise e Projeto Orientados por Objetos Análise e Projeto Orientados por Objetos Aula 02 Análise e Projeto OO Edirlei Soares de Lima Análise A análise modela o problema e consiste das atividades necessárias para entender

Leia mais

Curso de PHP. FATEC - Jundiaí. A programação orientada a objetos (object-oriented oriented programming

Curso de PHP. FATEC - Jundiaí. A programação orientada a objetos (object-oriented oriented programming Curso de PHP FATEC - Jundiaí A programação orientada a objetos (object-oriented oriented programming OOP) é um conjunto de técnicas t para organizar o código c em torno de entidades ou objetos representados

Leia mais

Projeto de Arquitetura

Projeto de Arquitetura Projeto de Arquitetura Ian Sommerville 2006 Engenharia de Software, 8ª. edição. Capítulo 11 Slide 1 Objetivos Apresentar projeto de arquitetura e discutir sua importância Explicar as decisões de projeto

Leia mais

Programação Orientada a Objetos Classes Abstratas Técnico em Informática. Prof. Marcos André Pisching, M.Sc.

Programação Orientada a Objetos Classes Abstratas Técnico em Informática. Prof. Marcos André Pisching, M.Sc. Classes Abstratas Técnico em Informática, M.Sc. Classes Abstratas 2 Classes Abstratas Abstração Devemos considerar as qualidades e comportamentos independentes dos objetos a que pertencem, isolamos seus

Leia mais

Teste de Software. Ricardo Argenton Ramos ricargentonramos@gmail.com. Engenharia de Software I 2012.2

Teste de Software. Ricardo Argenton Ramos ricargentonramos@gmail.com. Engenharia de Software I 2012.2 Teste de Software Ricardo Argenton Ramos ricargentonramos@gmail.com Engenharia de Software I 2012.2 O que diferencia teste de software OO de testes Convencionais? Técnicas e abordagens são normalmente

Leia mais

Projeto de Sistemas I

Projeto de Sistemas I Instituto Federal de Educação, Ciência e Tecnologia de São Paulo Projeto de Sistemas I Professora: Kelly de Paula Cunha E-mail:kellypcsoares@ifsp.edu.br Requisitos: base para todo projeto, definindo o

Leia mais

AULA 4 VISÃO BÁSICA DE CLASSES EM PHP

AULA 4 VISÃO BÁSICA DE CLASSES EM PHP AULA 4 VISÃO BÁSICA DE CLASSES EM PHP Antes de mais nada, vamos conhecer alguns conceitos, que serão importantes para o entendimento mais efetivos dos assuntos que trataremos durante a leitura desta apostila.

Leia mais

Projeto de Arquitetura

Projeto de Arquitetura Introdução Projeto de Arquitetura (Cap 11 - Sommerville) UNIVERSIDADE FEDERAL DE ALAGOAS Curso de Ciência da Computação Engenharia de Software I Prof. Rômulo Nunes de Oliveira Até agora, estudamos: Os

Leia mais

Autoria:Aristófanes Corrêa Silva Adaptação: Alexandre César M de Oliveira

Autoria:Aristófanes Corrêa Silva Adaptação: Alexandre César M de Oliveira Unified Modeling Language (UML) Universidade Federal do Maranhão UFMA Pós Graduação de Engenharia de Eletricidade Grupo de Computação Assunto: Introdução Autoria:Aristófanes Corrêa Silva Adaptação: Alexandre

Leia mais

Design Patterns. Viviane Torres da Silva viviane.silva@ic.uff.br. http://www.ic.uff.br/~viviane.silva/2012.1/es1

Design Patterns. Viviane Torres da Silva viviane.silva@ic.uff.br. http://www.ic.uff.br/~viviane.silva/2012.1/es1 Design Patterns Viviane Torres da Silva viviane.silva@ic.uff.br http://www.ic.uff.br/~viviane.silva/2012.1/es1 Sumário Reuso de Software Introdução Benefícios e Desvantagens Visão do Reuso Padrões de Projeto

Leia mais

Unisant Anna Gestão Empresarial com ERP 2014 Modelagem de Sistemas - UML e MER

Unisant Anna Gestão Empresarial com ERP 2014 Modelagem de Sistemas - UML e MER Objetivo dessa aula é descrever as características e a simbologia dos diagramas UML e MER na modelagem de sistemas de informação de uma forma a permitir a comunicação entre técnicos e gestores. Modelagem

Leia mais

Esta dissertação apresentou duas abordagens para integração entre a linguagem Lua e o Common Language Runtime. O objetivo principal da integração foi

Esta dissertação apresentou duas abordagens para integração entre a linguagem Lua e o Common Language Runtime. O objetivo principal da integração foi 5 Conclusão Esta dissertação apresentou duas abordagens para integração entre a linguagem Lua e o Common Language Runtime. O objetivo principal da integração foi permitir que scripts Lua instanciem e usem

Leia mais

UML 2. Guia Prático. Gilleanes T.A. Guedes. Novatec. Obra revisada e ampliada a partir do título Guia de Consulta Rápida UML 2

UML 2. Guia Prático. Gilleanes T.A. Guedes. Novatec. Obra revisada e ampliada a partir do título Guia de Consulta Rápida UML 2 UML 2 Guia Prático Gilleanes T.A. Guedes Obra revisada e ampliada a partir do título Guia de Consulta Rápida UML 2 Novatec capítulo 1 Introdução à UML A UML (Unified Modeling Language ou Linguagem de Modelagem

Leia mais

Persistência e Banco de Dados em Jogos Digitais

Persistência e Banco de Dados em Jogos Digitais Persistência e Banco de Dados em Jogos Digitais Prof. Marcos Francisco Pereira da Silva Especialista em Engenharia de Software Jogos Digitais - Computação Gráfica 1 Agenda Vantagens de usar a abordagem

Leia mais

Capítulo X. Gerenciar Mudanças dos Requisitos. Aluizio Saiter, M. Sc.

Capítulo X. Gerenciar Mudanças dos Requisitos. Aluizio Saiter, M. Sc. Capítulo X Gerenciar Mudanças dos Requisitos., M. Sc. 2 1. Sobre a disciplina de gerência de requisitos. 2. Boas práticas em engenharia de software. 3. Introdução a gerência de requisitos. 4. Introdução

Leia mais

Eduardo Bezerra. Editora Campus/Elsevier

Eduardo Bezerra. Editora Campus/Elsevier Princípios de Análise e Projeto de Sistemas com UML 2ª edição Eduardo Bezerra Editora Campus/Elsevier Capítulo 11 Arquitetura do sistema Nada que é visto, é visto de uma vez e por completo. --EUCLIDES

Leia mais

Processos de Desenvolvimento de Software

Processos de Desenvolvimento de Software Processos de Desenvolvimento de Software Gerenciamento de Projetos Mauro Lopes Carvalho Silva Professor EBTT DAI Departamento de Informática Campus Monte Castelo Instituto Federal de Educação Ciência e

Leia mais

AUTOR: DAVID DE MIRANDA RODRIGUES CONTATO: davidmr@ifce.edu.br CURSO FIC DE PROGRAMADOR WEB VERSÃO: 1.0

AUTOR: DAVID DE MIRANDA RODRIGUES CONTATO: davidmr@ifce.edu.br CURSO FIC DE PROGRAMADOR WEB VERSÃO: 1.0 AUTOR: DAVID DE MIRANDA RODRIGUES CONTATO: davidmr@ifce.edu.br CURSO FIC DE PROGRAMADOR WEB VERSÃO: 1.0 SUMÁRIO 1 Conceitos Básicos... 3 1.1 O que é Software?... 3 1.2 Situações Críticas no desenvolvimento

Leia mais

Algoritmos e Programação (Prática) Profa. Andreza Leite andreza.leite@univasf.edu.br

Algoritmos e Programação (Prática) Profa. Andreza Leite andreza.leite@univasf.edu.br (Prática) Profa. Andreza Leite andreza.leite@univasf.edu.br Introdução O computador como ferramenta indispensável: Faz parte das nossas vidas; Por si só não faz nada de útil; Grande capacidade de resolução

Leia mais

Programação com Objectos

Programação com Objectos Programação com Objectos PADRÕES DE DESENHO Classificaçã Objectivo Criação Estrutura Comportamento Introdução Alguns Padrões de Desenho Classe Factory Method Adapter Interpreter Template Method O que é

Leia mais

Histórico da Orientação a Objetos Ciclo de vida de Desenvolvimento de SW

Histórico da Orientação a Objetos Ciclo de vida de Desenvolvimento de SW Histórico da Orientação a Objetos Ciclo de vida de Desenvolvimento de SW Baseado nos materiais dos profs: Prof.: Edilberto M. Silva http://www.edilms.eti.br Edna Canedo Marcio de Carvalho Victorino Brasília-DF,

Leia mais

Rock In Rio - Lisboa

Rock In Rio - Lisboa Curso de Engenharia Informática Industrial Rock In Rio - Lisboa Elaborado por: Ano Lectivo: 2004/05 Tiago Costa N.º 4917 Turma: C Gustavo Graça Patrício N.º 4757 Turma: C Docente: Professora Maria Estalagem

Leia mais

Engenharia de Software I: Análise e Projeto de Software Usando UML

Engenharia de Software I: Análise e Projeto de Software Usando UML Engenharia de Software I: Análise e Projeto de Software Usando UML Capítulo 1 Processo de Desenvolvimento de Software Metodologia de Desenvolvimento de Software Uma metodologia é um conjunto de métodos,

Leia mais

Tópicos em Engenharia de Computação

Tópicos em Engenharia de Computação Tópicos em Engenharia de Computação Introdução / Revisão UML e POO (JAVA) Prof. Ivan Prof. Zagari UML Linguagem Unificada. Não é metodologia, processo ou método. Versão atual 2.0 3 categorias de Diagramas

Leia mais

PEN - Processo de Entendimento das Necessidades de Negócio Versão 1.4.0

PEN - Processo de Entendimento das Necessidades de Negócio Versão 1.4.0 PEN - Processo de Entendimento das Necessidades de Negócio Versão 1.4.0 Banco Central do Brasil, 2015 Página 1 de 14 Índice 1. FLUXO DO PEN - PROCESSO DE ENTENDIMENTO DAS NECESSIDADES DE NEGÓCIO... 3 2.

Leia mais

Universidade Paulista

Universidade Paulista Universidade Paulista Ciência da Computação Sistemas de Informação Gestão da Qualidade Principais pontos da NBR ISO/IEC 12207 - Tecnologia da Informação Processos de ciclo de vida de software Sergio Petersen

Leia mais

Modelo Cascata ou Clássico

Modelo Cascata ou Clássico Modelo Cascata ou Clássico INTRODUÇÃO O modelo clássico ou cascata, que também é conhecido por abordagem top-down, foi proposto por Royce em 1970. Até meados da década de 1980 foi o único modelo com aceitação

Leia mais