DEV Community

Higor Diego
Higor Diego

Posted on

Padrão - Prototype

Pattern Prototype

O padrão Prototype foi criado por Gamma et al. em seu livro "Design Patterns: Elements of Reusable Object-Oriented Software", publicado em 1995. Este padrão Prototype é um padrão de projeto criacional em desenvolvimento de software.

Ele é usado para criar novos objetos copiando objetos existentes, em vez de criar novos objetos do zero. O objetivo desse padrão é reduzir a complexidade da criação de objetos e permitir que novos objetos sejam criados sem especificar suas classes. Ele é uma boa prática para lidar com problemas de criação de objetos complexos, e pode ser usado para facilitar a implementação de mecanismos de cópia superficial e profunda de objetos.

O padrão é implementado criando uma interface "Prototype" que define um método "clone" para criar cópias de um objeto. Classes concretas implementam esse método para criar cópias de si mesmas. Esse padrão é útil quando criar novos objetos pode ser custoso ou impraticável, como quando os objetos precisam ser criados em tempo de execução ou quando os objetos são instanciados dinamicamente.

O padrão Prototype tem várias vantagens, incluindo:

  • Criação de objetos sem especificar suas classes: O padrão permite que novos objetos sejam criados sem especificar suas classes, o que significa que as classes precisam ser definidas apenas uma vez e depois podem ser usadas para criar novos objetos. Isso ajuda a manter o código limpo e fácil de manter.
  • Redução da complexidade da criação de objetos: O padrão ajuda a reduzir a complexidade da criação de objetos, permitindo que objetos sejam criados rapidamente e facilmente.
  • Possibilidade de criação de objetos em tempo de execução: O padrão permite que objetos sejam criados em tempo de execução, o que significa que novos objetos podem ser criados dinamicamente.
  • Suporte para cópias superficial e profunda: O padrão suporta a criação de cópias superficial e profunda de objetos. A cópia superficial cria uma cópia do objeto, mas compartilha os mesmos dados subjacentes. A cópia profunda cria uma cópia completa do objeto e dos dados subjacentes.
  • Reutilização de código: O padrão permite que o código já escrito e testado seja reaproveitado para criar novos objetos, o que ajuda a economizar tempo e esforço.
  • Fácil de mudar implementação: como os objetos são criados a partir de protótipos já existentes, é fácil de mudar a implementação sem precisar refatorar grande parte do código
  • Flexibilidade: o uso do padrão prototype nos permite mudar o comportamento ou estado de uma classe sem precisar modificar o código fonte
  • Baixo acoplamento: O padrão tem um baixo acoplamento entre as classes, o que significa que as classes são independentes umas das outras e podem ser facilmente modificadas ou substituídas sem afetar outras classes.

Segue abaixo um simples exemplo de código usando o padrão Prototype.


// Interface Prototype
class Prototype {
    clone() {}
}

// Concrete Prototype
class ConcretePrototypeA extends Prototype {
    constructor(name) {
        super();
        this.name = name;
    }
    clone() {
        return new ConcretePrototypeA(this.name);
    }
}

// Usage
let prototypeA = new ConcretePrototypeA("Prototype A");
let copyOfPrototypeA = prototypeA.clone();
console.log(copyOfPrototypeA.name); // Output: "Prototype A"

Enter fullscreen mode Exit fullscreen mode

Neste exemplo, a classe Prototype é uma interface que define o método clone. A classe ConcretePrototypeA é uma implementação concreta da classe Prototype e implementa o método clone para criar uma cópia do objeto.
Na usagem, um objeto ConcretePrototypeA é criado e armazenado na variável prototypeA, e logo depois ele é clonado para outro objeto e armazenado na variável copyOfPrototypeA.

Como mencionado anteriormente, essa forma de implementar pode ser uma forma de fazer cópias profundas, mas é importante lembrar que esse padrão tem varias formas de ser implementado, e algumas bibliotecas já possuem implementações de clones de objetos, por exemplo lodash.cloneDeep().

Simples, né ?

Imagine outro cenário no qual precisa realizar uma busca e uma inserção de dados via formulário atraves de um ponto de entrada que é uma API.

Api listada foi:

Segue a solução abaixo:

// Interface Prototype
class Request {
    constructor(url) {
        this.url = url;
    }
    clone() {}
    makeRequest() {}
}

// Concrete Prototype
class GetRequest extends Request {
    constructor(url) {
        super(url);
    }
    clone() {
        return new GetRequest(this.url);
    }
    makeRequest() {
        return fetch(this.url).then((response) => response.json())
    }
}

class PostRequest extends Request {
    constructor(url, body) {
        super(url);
        this.body = body;
    }
    clone() {
        return new PostRequest(this.url, this.body);
    }
    makeRequest() {
        return fetch(this.url, { 
            method: 'POST', 
            headers: { 'Content-Type': 'application/json'}, 
            body: JSON.stringify(this.body)
        }).then((response) => response.json())
    }
}

// Usage
let getRequest = new GetRequest("https://reqres.in/api/users");
let postRequest = new PostRequest("https://reqres.in/api/users", { "name": "morpheus", "job": "leader" });

let requests = [getRequest, postRequest, getRequest.clone(), postRequest.clone()];

requests.forEach(request => {
    request.makeRequest();
});

Enter fullscreen mode Exit fullscreen mode

A classe Request é uma interface de protótipo, que define o construtor e os métodos clone() e makeRequest(). As classes GetRequest e PostRequest são protótipos concretos, que estendem a classe Request e implementam seus próprios métodos clone() e makeRequest().

Na classe GetRequest, o método clone() retorna uma nova instância de GetRequest, com a mesma url que a instância atual. O método makeRequest() utiliza a função fetch() para realizar uma requisição GET à url especificada e retorna a resposta no formato JSON.

Na classe PostRequest, o método clone() retorna uma nova instância de PostRequest, com a mesma url e o mesmo corpo que a instância atual. O método makeRequest() utiliza a função fetch() para realizar uma requisição POST à url especificada, com o corpo especificado no construtor, e retorna a resposta no formato JSON.

No final do código, é criado uma instância de GetRequest e outra de PostRequest. Em seguida, é criado um array requests e adicionado as instâncias originais e suas cópias. Por fim, o método makeRequest() é chamado para todas as instâncias no array requests.

O padrão Prototype é útil quando você precisa criar novos objetos a partir de objetos existentes, sem precisar especificar sua classe ou seu tipo. Algumas situações em que o padrão Prototype pode ser aplicado incluem:

  • Quando a criação de novos objetos é custosa ou demorada, e é mais eficiente criar uma cópia de um objeto existente.
  • Quando os objetos precisam ser modificados dinamicamente, mas ainda precisam manter sua estrutura básica.
  • Quando você precisa criar várias instâncias de um objeto com pequenas variações, como alterar apenas alguns atributos.
  • Quando você precisa evitar o uso de vários construtores ou métodos estáticos para criar diferentes tipos de objetos.

Em geral, o padrão Prototype é uma boa escolha quando você precisa criar objetos de forma flexível e eficiente, sem precisar se preocupar com os detalhes de sua implementação.

Conclusão

O padrão de projeto Prototype é um padrão de criação que permite criar novos objetos a partir de objetos existentes, sem precisar especificar sua classe ou seu tipo. Isso é feito através da implementação de um método de clonagem que cria uma cópia do objeto original. Ele é útil quando a criação de novos objetos é custosa ou demorada, quando os objetos precisam ser modificados dinamicamente mas ainda precisam manter sua estrutura básica, quando é necessário criar várias instâncias de um objeto com pequenas variações ou quando é necessário evitar o uso de vários construtores ou métodos estáticos para criar diferentes tipos de objetos.

Espero ter ajudado, até a próxima.

Top comments (0)