Como Implementar Design Patterns em TypeScript: Prototype
O que é o Design Pattern Prototype?
O padrão de design Protótipo é um dos padrões de design criacional, que envolve a criação de objetos com base em um modelo de um objeto existente por meio de clonagem. Em vez de criar uma nova instância de um objeto do zero e configurá-lo, o padrão de protótipo permite copiar um objeto existente e possivelmente personalizá-lo.
Objetivo:
Especifica os tipos de objetos a serem criados usando uma instância prototípica e crie novos objetos copiando esse protótipo.
Aplicabilidade:
- Quando as classes a serem instanciadas são especificadas em tempo de execução, por exemplo, por carregamento dinâmico.
- Evitar a construção de uma hierarquia de classes de fábricas paralela à hierarquia de classes de produtos.
- Quando as instâncias de uma classe podem ter uma das poucas combinações diferentes de estado.
Vantagens:
- Subclasses reduzidas: O padrão de protótipo ajuda a reduzir o número de classes nomeadas que o sistema precisa, permitindo clonar um protótipo em vez de chamar um método de fábrica.
- Configuração dinâmica de uma aplicação que usa classes: Através do uso de protótipos, é possível instanciar e configurar objetos dinamicamente.
- Performance: Em cenários em que criar uma instância totalmente nova é mais caro do que copiar uma existente, usar o protótipo pode ser mais eficiente.
Desvantagens:
- A cópia profunda de objetos pode ser complexa, especialmente se as referências internas do objeto levarem a estruturas cíclicas.
- Nem todos os objetos podem ser clonados facilmente, dependendo de suas restrições de encapsulamento e estado interno.
Como implementar Prototype?
Vamos considerar um exemplo real onde o padrão de design Prototype pode ser útil: gerenciar formas gráficas em um aplicativo de desenho.
Imagine que você está criando um aplicativo de desenho e os usuários podem colocar formas como círculos, quadrados e linhas em uma tela.
Depois que uma forma é adicionada, os usuários podem querer criar duplicatas dessa forma com as mesmas propriedades, mas movê-las ou ajustá-las individualmente.
abstract class Shape {
x: number;
y: number;
color: string;
constructor(source?: Shape) {
if (source) {
this.x = source.x;
this.y = source.y;
this.color = source.color;
}
}
abstract clone(): Shape;
}
class Circle extends Shape {
radius: number;
constructor(source?: Circle) {
super(source);
this.radius = source ? source.radius : 0;
}
clone(): Circle {
return new Circle(this);
}
}
class Rectangle extends Shape {
width: number;
height: number;
constructor(source?: Rectangle) {
super(source);
this.width = source ? source.width : 0;
this.height = source ? source.height : 0;
}
clone(): Rectangle {
return new Rectangle(this);
}
}
Agora vamos usar estas classes:
// Cria uma instância de Circle
let circle: Circle = new Circle();
circle.x = 10;
circle.y = 10;
circle.radius = 20;
circle.color = "red";
// Clona circle
let anotherCircle: Circle = circle.clone();
anotherCircle.x = 20; // move the cloned circle to a different position
// Cria uma instância de Rectangle
let rectangle: Rectangle = new Rectangle();
rectangle.x = 5;
rectangle.y = 5;
rectangle.width = 50;
rectangle.height = 30;
rectangle.color = "blue";
// Clona rectangle
let anotherRectangle: Rectangle = rectangle.clone();
anotherRectangle.width = 60; // change the width of the cloned rectangle
// Neste momento, we temos as formas original e clonada com algumas propriedades compartilhadas e algumas alteradas.
Neste exemplo, o padrão Prototype permite a criação fácil e eficiente de novos objetos de forma que carregam as propriedades das formas existentes, mas podem ser modificados individualmente.
Ao considerar o padrão de protótipo, é essencial avaliar os prós e os contras no contexto dos requisitos e complexidades específicos da aplicação em questão.