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"
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();
});
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)