Como Implementar Design Patterns em TypeScript: Prototype
O que é o Design Pattern Prototype?
O design pattern Prototype é um padrão de projeto criacional usado quando o tipo de objetos a criar é determinado por uma instância prototípica, que é clonada para produzir novos objetos.
Este padrão é usado para:
- Evitar subclasses de um criador de objeto no aplicativo cliente, como faz o padrão fábrica abstrata.
- Evitar o custo inerente de criar um novo objeto da maneira padrão (por exemplo, usando a palavra-chave ‘new’) quando for proibitivamente caro para um determinado aplicativo.
Para implementar o padrão, você declara uma classe base abstrata que especifica um método clone virtual puro. Qualquer classe que precise de um recurso de “construtor polimórfico” deriva-se da classe base abstrata e implementa a operação de clonagem.
O cliente, em vez de escrever um código que invoque o operador “new” em um nome de classe codificado, chama o método clone no protótipo, chama um método de fábrica com um parâmetro que designa a classe derivada concreta específica a ser instanciada ou invoca o método clone por meio de algum mecanismo fornecido por outro padrão de design.
O design pattern Prototype oferece várias vantagens:
Desempenho: Se a criação de um novo objeto for uma operação cara, o padrão de projeto prototype ajuda a melhorar o desempenho clonando/copiando os objetos existentes, em vez de criar novos.
Configuração Dinâmica: Este padrão possibilita uma configuração mais dinâmica de uma aplicação. Em vez de codificar o tipo de objeto a ser criado, o aplicativo pode clonar objetos em tempo de execução.
Variedade de Classes Derivadas: O padrão permite que o cliente crie cópias de objetos concretos arbitrários, não apenas instâncias de uma família relacionada por uma interface comum. Portanto, ele pode ser usado para instanciar uma variedade de classes derivadas.
Preservar o estado existente: quando um objeto é clonado, o objeto clonado carrega o estado do objeto original. Isso pode ser útil se você quiser criar um novo objeto com o estado de um objeto existente.
Facilidade de uso com objetos complexos: para objetos complexos que levam muito tempo para instanciar e configurar, e que também podem exigir interações de API complexas, os protótipos podem simplificar e acelerar drasticamente o processo de criação de mais desses objetos.
No entanto, tenha em mente que esse padrão tem seus trade-offs. A clonagem profunda (deep clone) pode ser uma operação cara para objetos complexos e pode consumir muita memória, e pode ser complicada ao lidar com objetos que possuem referências circulares ou contêm recursos que não podem ser copiados facilmente, como manipuladores de arquivos ou conexões de banco de dados.
Como implementar Prototype?
No TypeScript, o padrão Prototype pode ser implementado usando um método clone em uma classe. Aqui está um exemplo simples:
interface Prototype {
clone(): Prototype;
sayHello(): void;
}
class ConcretePrototype implements Prototype {
private message: string;
constructor(message: string) {
this.message = message;
}
public clone(): Prototype {
return new ConcretePrototype(this.message);
}
public sayHello(): void {
console.log(this.message);
}
}
function clientCode(): void {
const prototype1: Prototype = new ConcretePrototype('Hello, World!');
prototype1.sayHello();
const prototype2: Prototype = prototype1.clone();
prototype2.sayHello();
}
clientCode();
Neste exemplo, ConcretePrototype
é a classe que é clonada. O método clone
cria um novo ConcretePrototype
usando a mesma message
da instância atual.
A função clientCode
cria uma instância de ConcretePrototype
e a clona. Apesar de prototype1
e prototype2
serem instâncias diferentes, elas foram criadas sem usar diretamente a palavra-chave new
em ConcretePrototype
dentro de clientCode
. Isso significa que o tipo exato do objeto não precisa ser conhecido pelo clientCode
, seguindo o padrão Prototype.
Este é um exemplo muito simplificado. Em um projeto real, o padrão Prototype pode ser útil para objetos complexos cuja criação é cara ou quando você precisa criar objetos dinamicamente em tempo de execução.