Padrão - Prototype
Tags: javascript, webdev, cleancode, programming
Published: 2023-01-14 15:13:07

![Pattern Prototype](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/dizveowajcjn5fdk1rlo.png)

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.

```js

// 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"

```

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:

- [ReqRes](https://reqres.in/)


Segue a solução abaixo:

```js
// 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();
});

```

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.