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.

SurveyJS custom survey software

JavaScript UI Libraries for Surveys and Forms

SurveyJS lets you build a JSON-based form management system that integrates with any backend, giving you full control over your data and no user limits. Includes support for custom question types, skip logic, integrated CCS editor, PDF export, real-time analytics & more.

Learn more

Top comments (0)

Sentry image

See why 4M developers consider Sentry, “not bad.”

Fixing code doesn’t have to be the worst part of your day. Learn how Sentry can help.

Learn more

👋 Kindness is contagious

Please leave a ❤️ or a friendly comment on this post if you found it helpful!

Okay