Padrões de projeto - Desenho-1-2018-G-6/docs GitHub Wiki
| Data | Versão | Modificação | Autor |
|---|---|---|---|
| 09/05/2018 | 1.0 | Inicialização do documento | Lucas Malta |
| 10/05/2018 | 1.1 | Inserção do State no documento | Thalisson Melo |
| 14/05/2018 | 1.2 | Descrição do padrão composite | Lucas Martins |
| 14/05/2018 | 1.3 | Descrição do padrão strategy | Guilherme Augusto |
| 14/05/2018 | 2.0 | Descrição dos padrões grasp identificados | Lucas Martins |
Sumário
Padrões de Projeto GOF
Este documento tem como objetivo explicitar os padrões de projeto utilizados nesta aplicação nos níveis de modelagem e de implementação, bem como a motivação para o uso dos mesmos.
1. Decorator
O padrão de projeto decorator visa anexar responsabilidades adicionais a um objeto de modo dinâmico. Desse modo, um objeto pode ter novos atributos e/ou métodos sem a necessidade de deletá-lo/recriá-lo.
Esse padrão foi introduzido em nossa aplicação no contexto de Usuário - Administrador. Um usuário, ao ser criado, contém os atributos e métodos somente de um usuário comum. Contudo, esse mesmo usuário pode adquirir o status de um administrador, dada as motivações do dono da aplicação. Sendo assim, é necessário que, dinamicamente, esse usuário adquira o status de administrador, herdando assim os atributos e métodos relacionados ao mesmo. Outros padrões poderiam ser aplicados, como o facade ou até mesmo um padrão de criação como o builder, mas achamos a ideia do Decorator mais interessante, pela possibilidade de adicionar/remover métodos e atributos dinamicamente à um objeto.

Dada as limitações do framework/linguagem, a aplicação do padrão decorator teve algumas mudanças para que o mesmo se adequa-se ao ambiente. A primeira limitação se refere à maneira que o decorator injeta novas "subclasses" à classe principal. Como a herança do rails é limitada (Além de não se existir uma classe abstrata propriamente dita), tivemos que optar por utilizar um campo chamado "user_type". Esse campo (String), contém os tipos de decorators que estão sendo adicionados. Na aplicação atual, só temos um tipo de decorator, o admin. Mas caso houvesse mais, poderiamos adicionar ao user_type: "admin manager seller", que o usuário obteria os métodos e atributos de manager e seller.
create_table "users", force: :cascade do |t|
t.string "first_name"
t.string "last_name"
t.string "email"
t.string "cpf"
t.date "birth_date"
t.string "gender"
t.string "phone"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.string "password_digest"
t.string "user_type"
end
Adicionado o tipo de usuário no campo, o mesmo "herda" os métodos e atributos da classe definida. Desse modo, definimos:
class UserDecorator < Draper::Decorator
include Draper::LazyHelpers
delegate_all
def show_sidebar
if current_user.user_type.include? "admin"
render :partial => "users/admin_sidebar"
end
end
def show_edit_buttons
if current_user.user_type.include? "admin"
return true
else
return false
end
end
Esses 2 métodos são para usuários que foram decorados com a classe de Admin. Esses usuários podem utilizar os métodos show_sidebar e show_edit_buttons, que são métodos que liberam o uso de outras funcionalidades específicas para administrador, como adição/remoção de produtos.
2. State
O padrão de projeto State visa armazenar o estado de um objeto da aplicação para que este defina uma mudança no comportamento do objeto de acordo com seu o estado.
Este padrão foi inserido na nossa aplicação no contexto do estado do carrinho, pois este tem um comportamento diferente se estiver cheio ou vazio, e futuramente terá o estado de em pagamento e de pagamento finalizado, cada um desses estados resulta em mostar para o usuário diferentes informações.
Se não houver itens no carrinho a seguinte mensagem aparece:
"Seu carrinho está vazio, por farvor, volte e adicione produtos."
se houver produtos no carrinho eles são listados.
Esse padrão é aplicado da seguinte forma:
Há uma classe mãe chamada Cart que possui o método "status", o qual é sobrescrito pelas classes filhas InProgressState e EmptyState. Esse método sobrescrito retornam uma string com o estado atual, e esse estado define o comportamento do objeto do carrinho.
OrderStatus class:
class Cart < ActiveRecord::Base
def status
nil
end
end
InProgressState class:
class InProgressState < Cart
def status
"In Progress"
end
end
EmptyState:
class EmptyState < Cart
def status
"Empty"
end
end
Diagrama:

3. Composite
No contexto abordado pelo projeto, muitas vezes um produto a ser adquirido pelo cliente é composto de outros produtos. Um exemplo disso é um computador, que pode ser montado utilizando diversas peças e componentes diferentes. Para representar isto na aplicação, utilizou-se o padrão de projeto GOF Composite.
O Composite consiste em numa composição de objetos em uma árvore de estruturas, representando uma hierarquia de todo-parte, tratando assim um objeto como a composição de vários objetos de forma homogênea.
O padrão, como se pode ver no diagrama abaixo, consiste em uma classe Setup, que serve como interface para o Composite. Ela permite que a classe Category mantenha instâncias de objetos da classe leaf, classe Product no caso, ou da própria classe Category.

A aplicação deste padrão permite que o usuário construa seus produtos de forma personalizada, e compre o item mais adequado para suas necessidades.
4. Strategy
Relacionado ao projeto, existe a ideia de que, ao cliente finalizar a compra dos produtos desejados, ele escolhe a forma de pagamento desejada, podendo, no contexto do ecommerce Mamid, ser pagamento por cartão de crédito ou pagamento pela plataforma do PagSeguro.
O Strategy, no contexto abordado, permite de maneira simples, a variação dos algoritmos utilizados na resolução de um determinado problema, que, no caso, é em relação ao pagamento.
A estratégia de ramificar os tipos de pagamento, criando classes para cada uma, diminui o acoplamento do sistema, pois ao realizar a herança entre cada estratégia, evita a composição entre a classe pagamento e a classe anteriormente citada no diagrama anteriormente criado, inerente a tipo de pagamento.

Padrões de Projeto GRASP
1. Criador
Este padrão é aplicado quando uma classe é responsável por criar instâncias de outra classe.
Em geral, uma classe B deve ser responsável por criar instâncias de classe A se uma, ou preferencialmente mais, das seguintes afirmações se aplicam:
- Instâncias de B contêm ou agregam instâncias de A;
- Instâncias de B gravam instâncias de A;
- Instâncias de B utilizam de perto instâncias de A;
- Instâncias de B têm as informações de inicialização das instâncias de A e passam isso na criação.
Este padrão é aplicado em várias partes do sistema. Um exemplo de aplicação é na relação entre Product e Setup.
2. Especialista da Informação
Especialista na Informação é uma abordagem genérica que visa atribuir a responsabilidade de fazer ou conhecer algo ao "especialista", ou seja, à classe que possui a informação necessária para cumprir tal responsabilidade.
Este padrão foi aplicado nas mesmas classes onde existe o padrão Criador.
3. Alta Coesão
Alta coesão é um padrão que tenta manter os objetos adequadamente focados, gerenciáveis e compreensíveis. Significa que as responsabilidades de um determinado elemento do sistema estão altamente relacionadas e focadas em um contexto específico. Isto evita a classes que possuem várias responsabilidades distintas, não relacionadas, o que resulta em um sistema difícil de compreender e com a manutenibilidade baixa.
Todo o sistema foi desenvolvido visando a Alta Coesão, sempre delegando responsabilidades específicas e relacionadas para as classes, com o objetivo de prover uma maior manutenibilidade e tornar a compreensão do sistema mais fácil.
4. Baixo Acoplamento
O acoplamento é uma medida de quão forte um elemento está conectado, tem conhecimento ou depende de outros elementos. O padrão Baixo Acoplamento tem o objetivo de garantir uma menor dependência entre classes, maior potencial de reutilização de software, e permitir que mudanças em uma classe tenha menor impacto em outras.
Assim como a Alta Coesão, o Baixo Acoplamento foi sempre considerado durante a implementação do sistema, para garantir a manutenibilidade, diminuindo o custo de mudanças no sistema, e a reutilização de código.
5. Polimorfismo
O Polimorfismo consiste em definir a variação dos comportamentos com base em superclasses para o qual essa variação ocorre. Em outras palavras, este padrão é aplicado quando subclasses de uma superclasse são capazes de invocar métodos, que comportam-se de maneira diferente para cada classe derivada. Este padrão fornece mais flexibilidade ao sistema, pois permite que objetos do mesmo "tipo" adquiram comportamentos diferentes.
O Polimorfismo é a base para quase todos os Padrões de Projeto GOF, e pode ser encontrado em muitas partes do Mamid.
6. Invenção Pura
Uma Invenção Pura é uma classe artificial que não representa um conceito no domínio do problema, especialmente feito para conseguir baixo acoplamento, alta coesão e o potencial de reutilização.
7. Controlador
O padrão Controlador atribui a responsabilidade de lidar com os eventos do sistema para uma classe que representa a um cenário de caso de uso do sistema global.
Uma aplicação muito famosa deste padrão é encontrada no Padrão Arquitetural MVC. Como o sistema em questão é baseado na arquitetura MVC, pode-se dizer que o projeto foi "usuário" do padrão Controlador.