Link Search Menu Expand Document

GoFs Estruturais


  1. Adapter
    1. Modelagem
    2. Código Exemplo
  2. Composite
    1. Aplicabilidade
    2. Participantes
    3. Modelagem
    4. Código Exemplo
  3. Decorator
    1. Modelagem
    2. Código exemplo
  4. Referências

Versionamento

VersãoDataComentáriosAutor(es)
0.109/09/2021Abertura do documentoIgor Lima, Samuel Nogueira, Matheus Rodrigues e Roberto Nóbrega
0.210/09/2021Adicionando o AdapterMatheus Gabriel
1.010/09/2021RevisãoPedro Henrique
1.113/09/2021Adicionando CompositeSamuel Nogueira
1.213/09/2021Adicionando referências e revisãoMatheus Gabriel
1.315/09/2021Revisão CompositeEduardo Picolo
1.416/09/2021Adicionando conceito de Decorator e referênciasJoão Gabriel de Matos
1.516/09/2021Adicionando exemplo de codigo para DecoratorJoão Gabriel de Matos
2.018/09/2021Revisão DecoratorIgor Q Lima, Roberto M da Nóbrega
2.119/09/2021Corrgindo referenciasJoão Gabriel de Matos
2.219/09/2021Adicionando modelagem de DecoratorJoão Gabriel de Matos
3.019/09/2021Revisão Composite e AdapterGiovanna B Bottino

Adapter

Se trata de um padrão de projeto que auxilia na comunicação entre interfaces incompatíveis entre si, de maneira que possibilita que essa interação ocorra por meio de uma classe adaptadora.

Uma analogia frequentemente feita é a com o adaptador de tomada que possibilita a interação entre duas interfaces que são incompatíveis entre si. [1]

Modelagem

Código Exemplo

O código a seguir mostra uma aplicação do padrão Adapter fazendo a conversão de datas para diferentes formatos definidos a partir de templates pré existentes.

export type dateFormats = 'numeric' | 'long';

const dateAdapter = (date: Date, format: dateFormats = 'long'): string => {
  const formatMap = {
    numeric: {
      year: 'numeric',
      month: 'numeric',
      day: 'numeric',
    },
    long: {
      year: 'numeric',
      month: 'long',
      day: '2-digit',
    },
  };

  try {
    const formatedDate = new Intl.DateTimeFormat('pt-BR', formatMap[format] as Intl.DateTimeFormatOptions).format(
      new Date(date)
    );

    return formatedDate;
  } catch (error) {
    return '-';
  }
};

export default dateAdapter;

Composite

O padrão Composite é um padrão estrutural de objetos que tem como intenção compor objetos em estruturas de árvore para representarem hierarquias partes-todo. Permitindo aos clientes tratarem de maneira uniforme objetos individuais e composições de objetos.[2]

Aplicabilidade

Deve ser usado quando:

  • quiser representar hierarquias partes-todo de objetos.
  • quiser que os clientes sejam capazes de ignorar a diferença entre composições de objetos e objetos individuais. Todos os objetos na estrutura composta serão tratados de maneira uniforme.

Participantes

  1. Component - Declara e implementa o comportamento padrão para os objetos na composição, fornecendo uma interface para acessar e gerenciar os seus componentes-filhos.
  2. Leaf - representa objetos-folha, as quais não possuem filhos.
  3. Composite - define o comportamento para componentes que têm filhos, além de armazenar os componentes filhos.
  4. Client - O responsável por manipular objetos na composição através da interface Component.

Modelagem

Modelo básico de um Composite

Código Exemplo

O padrão Composite pode ser utilizado back-end do projeto para generalizar a forma como os Produtos são armazenados. No exemplo de código abaixo um classe abstrata Product é criada e herdada por SimpleProduct e CompositeProduct. SimpleProduct representa um produto simples que contem os atributos descritos na classe. Já CompositeProduct representa uma coleção de SimpleProducts e CompositeProducts. abaixo temos o diagrama do esquema de composite do exemplo.

Um exemplo de CompositeProduct dentro do escopo do projeto seria a criação de um Combo de produtos, comercializados como um, ou até mesmo um andaime(que é composto por painel, diagonal, escada, rodizio, etc).

class Product {
  products: Product[];
  add(child: Product): void {}
  remove(child: Product): void {}
  getChild(i) {
    return this.products[i];
  }
  totalPrice() {}
}

class SimpleProduct extends Product {
  private id: Number;
  private name: String;
  private description: String;
  private lastMaintenance: Date;
  private price: Number;
  private idCategory: Number;
  constructor(id, name, description, lastMaintenance, price, idCategory) {
    super();
    this.id = id;
    this.name = name;
    this.description = description;
    this.lastMaintenance = lastMaintenance;
    this.price = price;
    this.idCategory = idCategory;
  }

  public totalPrice() {
    return this.price;
  }
}

class CompositeProduct extends Product {
  products: Product[] = [];

  id: Number;
  name: String;
  constructor(id, name) {
    super();
    this.id = id;
    this.name = name;
  }

  public add(child) {
    this.products.push(child);
  }

  public remove(child) {
    for (let product, i = 0; (product = this.getChild(i)); i++) {
      if (product === child) {
        this.products.splice(i, 1);
        return true;
      }
    }
    return false;
  }

  totalPrice() {
    let result = 0;
    for (let product, i = 0; (product = this.getChild(i)); i++) {
      result += product.totalPrice();
    }

    return result;
  }
  discountPrice(percentage: any): Number {
    if (percentage > 1 && percentage < 0) {
      throw new Error('percentage value must be between 0 and 1');
    }
    const total: any = this.totalPrice();
    const discount = total * percentage;
    return total - discount;
  }
}

function main() {
  const comboBasico = new CompositeProduct(7, 'Combo de construção básico');

  const betoneira = new SimpleProduct(1, 'betoneira', '', new Date(), 220.0, 1);
  const carrinhoDeMao = new SimpleProduct(2, 'Carrinho de mão', '', new Date(), 100.0, 1);

  const andaime = new CompositeProduct(3, 'Conjunto de andaime simples');
  const painel = new SimpleProduct(4, 'painel', 'painel simples de andaime', new Date(), 9, 1);
  const diagonal = new SimpleProduct(5, 'diagonal', 'diagonal de andaime simples', new Date(), 5, 1);
  const escada = new SimpleProduct(6, 'Escada', 'Escada para andaime', new Date(), 8, 1);

  andaime.add(painel);
  andaime.add(painel);
  andaime.add(painel);
  andaime.add(painel);
  andaime.add(diagonal);
  andaime.add(escada);

  comboBasico.add(betoneira);
  comboBasico.add(carrinhoDeMao);
  comboBasico.add(andaime);
  const total = comboBasico.totalPrice();
  console.log(total);
}
main();

Decorator

É um padrão de projeto usado quando se deseja alterar o comportamento de um objeto, mas se prefere evitar as inconveniências do uso de herança (não poder alterar o comportamento de um objeto durante o tempo de execução — podendo apenas substitui-lo por outro criado de outra subclasse, e normalmente não ser possivel uma classe herdar o comportamento de múltiplas outras). Neste modelo se resolve este problema com o uso de “envoltórios”, sendo um objeto que implementa a mesma interface que o objeto alvo e delega para ele todos os pedidos/chamadas que recebe, mas fazendo alguma alteração antes ou após passar o pedido para o alvo.[3]

Modelagem

Código exemplo

Um exemplo de possivel uso de decorators, seria alterar o comportamento do metodo ‘validate’ da classe ‘Address’, quando o endereço ja se encontrar validado.


function validation(){
  return ( target: any,propertyKey: string,propertyDescriptor: PropertyDescriptor,)=>{
    if(!target["isValidated"]){
      descriptor.value.apply(this);
    }

  }
};

class Address{

  street:String;
  city:String;
  state:String;
  cep:Number;
  number:Number;
  complement:String;
  isValidated:Boolean;

  constructor(street,city,state,cep,number,complement,isValidated){
    this.street=street;
    this.city=city;
    this.state=state;
    this.cep=cep;
    this.number=number;
    this.complement=complement;
    this.isValidated=isValidated;
    validate();

}
  @validation
  validate(){
    //Validation logic
    ...
  }
  
}

Referências

Gamma, Erich. Padrões de projeto: soluções reutilizáveis de software orientado a objetos. 2007. Open WorldCat, http://site.ebrary.com/id/10824586.

[1] JavaScript Adapter Design Pattern - Dofactory. https://www.dofactory.com/javascript/design-patterns/adapter. Acessado 15 de setembro de 2021.

Refactoring Guru - Adapter. https://refactoring.guru/pt-br/design-patterns/adapter. Acessado 15 de setembro de 2021.

[2] JavaScript Composite Design Pattern - Dofactory. https://www.dofactory.com/javascript/design-patterns/composite. Acessado 14 de setembro de 2021.

JavaScript Decorator Design Pattern - Dofactory. https://www.dofactory.com/javascript/design-patterns/decorator. Acessado 16 de setembro de 2021.

[3] Refactoring Guru - Decorator. https://refactoring.guru/pt-br/design-patterns/decorator. Acessado 16 de setembro de 2021.

Typescript Handbook - Decorators. https://www.typescriptlang.org/docs/handbook/decorators.html. Acessado 16 de setembro de 2021.