Importância dos Padrões de Projeto no Desenvolvimento de Software

May 23, 2017 | Autor: Leonardo Barcelos | Categoria: Object Oriented Programming, Design Patterns
Share Embed


Descrição do Produto

Importância dos Padrões de Projeto no Desenvolvimento de Software Leonardo Machado Barcelos​1 1​

Centro Universitário Franciscano (UNIFRA) Rua dos Andradas, 1614 – 97010-032 – Santa Maria – RS – Brasil [email protected]

​ Abstract. This article aims to show the importance that design patterns are in software development, both in large projects as the small and present in a simplified way the families of design standards and the standards themselves. For this, recurring problems will be pointed that occur during the development process, and can be solved by the adoption of standards. During a development process, time is money, because of this, the design patterns are shown as a source of quick solution to common problems. Resumo. Este artigo tem por objetivo mostrar a importância que os padrões de projeto têm no desenvolvimento de softwares, tanto em projetos de grande porte quanto os de pequeno porte e apresentar de forma simplificada as famílias de padrões de projeto e os padrões em si. Para isto, serão apontados problemas recorrentes que ocorrem durante o processo de desenvolvimento, e que podem ser resolvidos com a adoção dos padrões. Durante um processo de desenvolvimento, tempo é dinheiro, em razão disto, os padrões de projeto mostram-se como uma fonte de solução rápida para problemas corriqueiros.



1. Introdução Um ​design pattern(Padrão de Projeto em tradução livre) pode ser definido como uma regra de três partes, que expressa a relação entre um contexto, um problema e uma solução [ALEXANDER, 1979]. Na década de 70 a ideia de ​Design Patterns foi introduzida por Chirstopher Alexander, mas com foco na Engenharia Civil e Arquitetura, e posteriormente popularizado na área de desenvolvimento pelos autores Erich Gamma, Richard Helm, Ralph Johnson e John Vlissides, ou GoF - Gang of Four, com o livro ​Design Patterns: Elements of Reusable Object-Oriented Software [ALUR et al, 2002]. Também podem ser apresentados como passos ou instruções para solução de um problema recorrente. Os padrões são organizados em famílias que podem ser: Padrões de Criação, Padrões Estruturais e Padrões Comportamentais. Além da família, são classificados segundo seu escopo, que pode ser: de Classe onde são definidas as relações entre as classes e ocorre no momento da compilação; e de Objeto onde são definidas as relações entre os objetos e ocorre durante a execução. Durante o processo de desenvolvimento de projetos orientados a objetos de grande e pequeno porte, surgem problemas que por inúmeras vezes já foram enfrentados por outros desenvolvedores. Muitos desses problemas podem ser “resolvidos” com a adoção dos padrões de projeto, pois estas são soluções que já foram testadas e aprovadas em determinado contexto. Criar soluções com base em padrões de projeto também gera uma maior reutilização de código, desde que bem implementado, pois essas soluções podem resolver problemas recorrentes dentro do próprio projeto. Além de apresentar soluções para problemas recorrentes os padrões de projeto fazem com que o projeto de software seja de fácil entendimento e manutenção.

2. Desenvolvimento Para entender a aplicação e a importância dos padrões de projeto, é necessário entendimento a respeito da Orientação a Objetos. 2.1. Paradigma Orientado a Objetos Orientação a objetos é um paradigma que apresenta toda uma filosofia para construção de sistemas que ao invés de construir um sistema formado por um conjunto de procedimentos e variáveis, lidamos com uma ótica mais próxima do mundo real, ou seja Objetos pelos quais temos uma maior compreensão [DALL’OGLIO, 2007]. No paradigma orientado a objetos lidamos com classes e objetos. As classes definem uma estrutura de dados, ou seja, ou template ou um modelo de como um dado deve ser, com atributos e métodos. Assim como representado na Figura 1, temos uma classe “Car” que define como um carro tem se comportar(métodos) e as características(atributos) desse carro; e as instâncias/objetos desta classe.

Figura 1. Classe e Objetos 2.1.1 Herança Na orientação a objetos e encapsulamento de código em classes, a estrutura de códigos acaba se tornando muito mais organizada e possibilita a reutilização de código. Com a herança, esta reutilização se da de forma mais eficiente, pois em uma hierarquia, as “classes filhas” herdam métodos e atributos das “classes mães”. A herança tem por objetivo tornar o código mais reutilizável, ou seja, ao invés de replicar os métodos e atributos comuns a mais de uma classe, cria-se uma mais genérica, e após as outras

estendem essa classe. Como mostrado na Figura 2, os métodos e atributos da classe Animal são “herdados” pelas classes “mamífero” e “Ave”, e assim por diante.

Figura 2. Modelo de Herança Na Figura 3 é possível identificar como a hierarquia de classes ficaria na estruturação do código na linguagem PHP. A classe “Animal” é a mais genérica e possui os métodos e atributos comum a todos os animais; em seguida cria-se as classes “Mamífero” e “Ave”, estendendo a classe “Animal” e assim herdando as características de um animal; o mesmo acontece para as classes “Homem”, “Cachorro” e “BeijaFlor”. Feito isto, pode-se dizer que todo Homem é um Mamífero, logo, além de executar a função de conversar e ter o atributo nome, ele executa a função de mamar; e como todo Mamífero é um animal, além de executar a função de mamar, ele também executa as funções de comer e dormir e tem o atributo idade. Essa é a ideia da Herança: as características e métodos das “classes mães” são passadas as suas “filhas”.

Figura 3. Implementação do modelo apresentado na Figura 2 em PHP.

2.1.2 Polimorfismo O significado da palavra polimorfismo nos remete a “muitas formas”. Em orientação a objetos é o princípio que permite que classes derivadas de uma mesma superclasse tenham métodos iguais(com a mesma nomenclatura e parâmetros), mas comportamentos diferentes, redefinidos em cada uma das classes-filha [DALL’OGLIO, 2007]. Como mostrado na Figura 4, a superclasse Animal possui um método comunicarSe que é herdado pela classe Cachorro e Gato. Ambas implementam o mesmo método, mas de maneiras diferentes.

Figura 4. Exemplo de Polimorfismo 2.1.2 Interfaces e Classes Abstratas Interfaces e Classes Abstratas definem comportamentos e características que uma classe deve seguir. Existem algumas peculiaridades que diferenciam interfaces e classes abstratas, mas a ideia geral é a mesma, ou seja, definir um “template” para a classe. Interfaces não possui implementações, apenas assinaturas de métodos ou constantes. Este tipo de entidade firma um tipo de “contrato”​, onde são especificados os atributos, métodos e funções que as classes que implementem essa interface são obrigadas a implementar. Classes Abstratas podem possuir implementações, mas não podem ser instanciadas. Definem métodos abstratos que obrigatoriamente devem ser implementados pelas sub-classes. 2.2 Padrões de Projeto ou Design Patterns Os padrões de projeto são classificados em famílias que podem ser estruturais, comportamentais e criacionais. Dentro destas classificações ainda são separados por contexto que pode ser Classe ou Objeto. 2.2.1 Padrões de Projeto de Criação

Padrões de Projeto de Criação estão encarregados de lidar com mecanismos de criação de objetos, tentando criar objetos de uma forma adequada a situação. A forma básica de criação de objetos pode resultar em problemas de projeto dependendo da complexidade. Os padrões criacionais vêm para resolver estes problemas. Estes são padrões de contexto de objeto. Existem vários padrões nesta família, tais como: Abstract Factory, Builder, FactoryMethod, Multiton, Pool, Prototype, SimpleFactory, Singleton e Static Factory. Abstract Factory: Este padrão se preocupa em criar série de objetos relacionados ou dependentes, sem especificar suas classes concretas. O “cliente” da abstract factory não se preocupa em como esses objetos serão criados, apenas em como eles se relacionam. Providencia um objeto de outra Factory que é responsável por criar os objetos necessários. Builder: Builder é responsável por construir partes de um objeto mais complexo. O tamanho da árvore hierárquica de Builders de um objeto é igual árvore hierárquica do objeto final. Factory Method: Factory Method delega a criação de objetos para sub-classes. Multiton: Considerado um “anti-padrão” o Multiton mantém uma lista de instâncias de cada objeto. Algo parecido com o padrão Singleton que será abordado adiante. Pool: O padrão Pool mantém um um grupo de objetos pré-inicializados prontos para serem usados, ao invés de de alocar e destrui-los sob demanda. Este padrão pode oferecer um ganho de desempenho significativo em casos onde o custo de inicialização de um objeto é alto. Prototype: Para evitar de criar objetos da maneira padrão, o que pode ser custoso quando se quer criar quantidades massivas de objetos, cria-se um Prototype e este é clonado n-vezes. Simple Factory: Responsável apenas por encapsular a cração de objetos. Singleton: Padrão no qual é gerado apenas um objeto que é usado em todo o sistema. Static Factory: Similar ao Abstract Factory, este padrão é utilizado para criar série de objetos relacionados ou dependentes. Adiferença entre este e o Abstract Factory é que o Static Factory utiliza somente um método estático para criar todos os tipos de objetos que ele pode criar. 2.2.2 Padrões de Projeto Estruturais Padrões de Projeto Estruturais tem por objetivo criar uma estrutura onde a percepção da relação entre as entidades é facilitada. Existem vários padrões nesta família, tais como: Adapter, Bridge, Composite, Data Maper, Decorator, Dependency Injection, Facade, Fluent Interface, Proxy e Registry. Adpter: Adapter “traduz” uma interface incompatível com uma classe em uma interface compatível. Um Adpter permite que classes trabalhem em conjunto quando normalmente isso não seria possível fornecendo suas interfaces para o cliente enquanto usa as originais. Bridge: Tem por finalidade desacoplar uma abstração de sua implementação para que ambos possam variar.

Composite: Permite o tratamento de um grupo de objetos como se fossem uma única instância. Data Maper: Um Data Maper, é uma camada de acesso a dados que realiza a transferência bidirecional de dados entre um armazenamento persistente de dados (muitas vezes um banco de dados relacional) e um na memória de representação de dados (a camada de domínio). O objetivo do padrão é manter a representação em memória persistente e o armazenamento de dados independente uns dos outros e do próprio Data Maper. A camada é composta por um ou mais mapeadores (ou Data Access Objects), realizando a transferência de dados. Decorator: Para adicionar dinamicamente uma nova funcionalidade para instâncias de classe. Dependency Injection: Para implementar uma arquitetura flexível, a fim de obter um melhor código testável, de fácil manutenção e extensível. Facade: Uma Facade é feita para separar um cliente e um sub-sistema, incorporando muitos (mas às vezes apenas uma) interface, e claro, para reduzir a complexidade. Fluent Interface: Para escrever código que é fácil legível apenas como frases em linguagem natural, geralmente em inglês. Proxy: Tem por finalidade agir como uma interface para tudo o que é custoso ou impossível de duplicar. Registry: Para implementar uma central de armazenamento para objetos usados frequentemente em todo o aplicativo, é tipicamente implementado usando uma classe abstrata com apenas métodos estáticos (ou usando o padrão Singleton). 2.2.3 Padrões de Projeto Comportamentais Padrões de Projeto Comportamentais são padrões de design que identificam padrões comuns de comunicação entre objetos e percebem esses padrões. Ao fazer isso, esses padrões aumentam a flexibilidade na realização dessa comunicação. Existem vários padrões nesta família, tais como: Chain of Responsibilities, Command, Iterator, Mediator, Memento, Null Object, Observer, Specification, State, Strategy, Template Method e Visitor. Chain Of Responsibilities: Para construir cadeias de objetos para manipular uma chamada em ordem sequencial. Se um objeto não consegue lidar com uma chamada ele delga esta chamada para próximo na cadeia e assim por diante. Command: Neste padrão tem-se um Invoker e um Receiver. Este padrão usa um “Command” para delegar a chamada do método em um “Receiver” onde ambos possuem o método execute. Um “Invoker” só conhece o método execute para processar o Command do cliente. O Receiver é desacoplado do Invoker. Um segundo aspecto deste padrão é o método “undo” que desfaz as ações realizadas com o comando “execute”. Command pode ser combinado a outros e fomar uma composição mais complexa.

Iterator: Serve para tornar um objeto iterável, ou seja, fazê-lo se parecer com um uma coleção de objetos. Mediator: Este padrão provê uma forma fácil para desacoplar muitos componentes trabalhando em conjunto. Memento: Este padrão possibilita que um estado anterior do objeto seja restaurado ou ganhar acesso ao estado do objeto, sem revelar sua implementação. NullObject: Usado apenas para identificar que o objeto é nulo. Serve para eliminar testes no código. Observer: Serve para implementar um comportamento de publish/subscribe para um objeto, ou seja, quando houver uma modificação este Observer será notificado. Specification: Serve para construção de regras de negócio limpas, onde objetos podem ser checados. A composição de classes de Specification tem um método chamado isSatisfiedBy que retorna true ou false dependendo se o objeto dado satisfaz a Specification. State: Encapsular o comportamento variável para a mesma rotina com base no estado de um objeto. Esta pode ser uma maneira mais limpa para um objeto para alterar o seu comportamento em tempo de execução, sem recorrer a grandes declarações condicionais complexas. Strategy: Para separar as estratégias e permitir a comutação rápida entre elas. TemplateMethod: Define o “esqueleto” de uma classe, ou seja, uma classe abstrata define a estrutura dos algoritmos e as sub-classes “terminam o trabalho”. Visitor: O padrão Visitor permite terceirizar operações em objetos a outros objetos. A principal razão para fazer isso é manter uma separação de interesses. Mas as classes tem que definir um contrato para permitir os visitantes.[FOWLER, 2003]

3. Conclusão Como o nível de reutilização de código é aumentado e por se tratar de soluções que já foram testadas e aprovadas, os padrões de projeto mostra-se como uma prática de extrema importância durante o desenvolvimento de software. Os padrões também são encorajados, pois mantém um padrão arquitetural de fácil entendimento, o que facilita futuras manutenções.

Referências ALEXANDER, C. The Timeless Way of Building. Oxford University Press, 1979. ALUR, D.; CRUPI, J.; MALKS, D. Core J2EETM patterns: as melhores práticas e estratégias de design. 2002. DALL’OGLIO, P. PHP: Programando com Orientação a Objetos. Novatec, 2007. FOWLER, M. Patterns of Enterprise Application Architectu., Addison Wesley, 2003.

Lihat lebih banyak...

Comentários

Copyright © 2017 DADOSPDF Inc.