Resumo : neste tutorial, você aprenderá como usar o padrão C# Prototype para criar novos objetos clonando os existentes.
Introdução ao padrão de protótipo C#
Em C#, as classes são modelos para a criação de novos objetos. Nas classes, você usa o new
operador para criar um objeto.
O padrão Prototype é um padrão de design criacional que permite criar novos objetos clonando objetos existentes. Em outras palavras, o padrão Prototype permite criar novos objetos a partir de objetos existentes, clonando-os sem especificar a classe exata dos objetos.
O padrão Prototype é útil quando você precisa criar novos objetos semelhantes aos existentes, mas com algumas diferenças em seu estado ou comportamento.
O padrão Prototype também é útil para criar um novo objeto complexo e que pode gerar sobrecarga. Portanto, você deseja evitar a complexidade e a sobrecarga clonando um objeto existente em vez de criar um novo do zero.
Para implementar o padrão Prototype, siga estas etapas:
- Primeiro, defina uma interface ou classe abstrata que especifique um método para clonar objetos.
- Segundo, crie classes concretas que implementem a interface ou estendam a classe abstrata. Cada classe concreta representa um tipo de objeto específico que pode ser copiado.
Para criar um novo objeto, primeiro chame o Clone()
método no objeto protótipo e depois modifique as propriedades do objeto clonado.
O diagrama UML a seguir ilustra como o padrão Prototype funciona.
O padrão Protótipo envolve os seguintes participantes:
- Protótipo : O protótipo pode ser uma interface ou uma classe abstrata . A interface Prototype (ou classe abstrata) possui o
Clone()
método que cria um novo objeto a partir de um objeto existente. - ConcretePrototype : Esta é uma classe concreta da interface Prototype. A
ConcretePrototype
classe implementa oClone()
método para clonar um objeto. - Cliente : Este é o código do cliente que utiliza a interface Prototype para criar novos objetos. O cliente cria um novo objeto clonando um objeto existente e depois personaliza o objeto clonado conforme necessário.
Exemplo de padrão de protótipo C#
O programa C# a seguir demonstra como usar o padrão Prototype criando um protótipo Warrior e clonando-o para criar um novo guerreiro com algumas diferenças em suas propriedades:
using static System.Console;
namespace PrototypePattern;
public interface IPrototype<T>
{
T Clone();
}
public class Warrior : IPrototype<Warrior>
{
public string Name { get; set; }
public int Health { get; set; }
public int AttackPower { get; set; }
public Warrior(string name, int health, int attackPower)
{
Name = name;
Health = health;
AttackPower = attackPower;
}
public override string ToString()
=> $"Name: {Name}, Health:{Health}, AttackPower: {AttackPower}";
public Warrior Clone() => (Warrior)MemberwiseClone();
}
public class Client
{
public static void Main(string[] args)
{
// Create an instance of the Warrior prototype
var loki = new Warrior("Loki", 100, 20);
// Clone the Loki warrior to create
// a new warrior named Thor
var thor = loki.Clone();
thor.Name = "Thor";
thor.Health = 120;
// Now we have two different warrior objects with
// similar properties but with some differences
WriteLine(loki);
WriteLine(thor);
}
}
Linguagem de código: C# ( cs )
Saída:
Name: Loki, Health:100, AttackPower: 20
Name: Thor, Health:120, AttackPower: 20
Linguagem de código: texto simples ( texto simples )
Como funciona.
Primeiro, defina uma interface chamada IPrototype
com um parâmetro de tipo genérico T
. O Prototype<T>
possui um método chamado Clone()
que será implementado pelo protótipo concreto para clonagem de um objeto:
public interface IPrototype<T>
{
T Clone();
}
Linguagem de código: C# ( cs )
Segundo, defina uma classe concreta Warrior
que implemente a IPrototype
interface. A Warrior
classe tem três propriedades Name
,, Health
e AttackPower
. Além disso, possui um construtor para inicializar estas propriedades:
public class Warrior : IPrototype<Warrior>
{
public string Name { get; set; }
public int Health { get; set; }
public int AttackPower { get; set; }
public Warrior(string name, int health, int attackPower)
{
Name = name;
Health = health;
AttackPower = attackPower;
}
public override string ToString()
=> $"Name: {Name}, Health:{Health}, AttackPower: {AttackPower}";
public Warrior Clone() => (Warrior)MemberwiseClone();
}
Linguagem de código: C# ( cs )
A classe Warrior substitui o ToString()
método para retornar uma representação de string do objeto warrior.
A classe Warrior também implementa o
método. O Clone()
método usa o Clone()
MemberwiseClone()
método que cria uma cópia superficial do Warrior
objeto.
Observe que o MemberwiseClone
método cria uma cópia superficial de um objeto criando um novo objeto e depois copiando os campos não estáticos do objeto para o novo objeto. Se um campo for um tipo de valor, ele executará uma cópia bit a bit do campo. Se um campo for um tipo de referência, ele copiará apenas a referência.
Como as propriedades da Warrior
classe são tipos de valor (exceto the string
, que é um tipo de referência, mas um caso especial), a cópia superficial é adequada nesse caso.
Terceiro, defina a Client
classe com o Main()
método como ponto de entrada principal do programa:
public class Client
{
public static void Main(string[] args)
{
// Create an instance of the Warrior prototype
var loki = new Warrior("Loki", 100, 20);
// Clone the Loki warrior to create
// a new warrior named Thor
var thor = loki.Clone();
thor.Name = "Thor";
thor.Health = 120;
// Now we have two different warrior objects with
// similar properties but with some differences
WriteLine(loki);
WriteLine(thor);
}
}
Linguagem de código: C# ( cs )
No Main()
método, criamos uma nova instância do Warrior
protótipo com nome Loki
, saúde 100
e poder de ataque 20
. Então clonamos o Loki
guerreiro usando o Clone()
método para criar um novo guerreiro chamado Thor
.
O Thor
guerreiro tem as mesmas propriedades que o Loki
guerreiro, exceto as propriedades Name
e Health
, que são definidas como Thor
e 120
, respectivamente.
A vantagem de usar o padrão Prototype é que você pode criar novos guerreiros com propriedades semelhantes a um existente sem especificar explicitamente a Warrior
classe. Conseqüentemente, o padrão Prototype oferece flexibilidade e reduz a duplicação de código.
Resumo
- Use o padrão Prototype para criar um novo objeto clonando um existente sem especificar explicitamente a classe dos objetos.
- Use o
MemberwiseClone
método para criar uma cópia superficial do objeto atual.