DESIGN - PADRÃO PROTOTIPO
Published: 2024-03-08 05:05:18

## Quem é o infeliz?
Basicamente, este padrão proporciona a um objeto a capacidade de ser clonado e faz parte de uma categoria que chamamos de padrões criacionais, pois eles são responsáveis por gerenciar criação de componentes/objetos (alguns exemplos são o Factory, Builder, Singleton e outros).

## Qual é o B.O.?
Dito isso, você deve estar se perguntando sobre o cenário em que o padrão deve ser aplicado e o motivo, então pensemos na seguinte situação: em uma parte qualquer do nosso código, temos uma função que recebe uma interface de um objeto qualquer, queremos então ter uma cópia dele e apenas fazer algumas alterações em seus atributos. Contudo, não sabemos muito sobre o que queremos clonar e isso nos traz alguns questionamentos. Será que há campos privados? Qual é a complexidade para a construção deste objeto? Isso iria nos deixar presos e dependentes deste objeto? E uma interface (entenda interface como um contrato que diz o que aquele objeto irá me fornecer), infelizmente, não consegue nos fornecer tais informações tão arraigadas ao objeto concreto (entenda concreto como a lógica que o objeto implementa dentro de si).

Imagine que você quer construir um carro que viu em uma foto, após bastante tempo você tem algo parecido, contudo faltam coisas (componentes internos) que você não consegue visualizar/acessar, devido a ter apenas uma foto para se basear, te impedindo de fazer uma reconstrução autêntica.

## Alguma solução?
A solução para isso seria dar ao objeto que queremos copiar o poder de se clonar, com esta habilidade não precisamos nos preocupar com os problemas citados acima.

Se a foto que temos do carro pudesse ter um botão de clonagem junto a ela, seria muito mais fácil :P

### Implementação
```
## 1 - interface definindo a capacidade/método de clonagem
interface IPrototipo<ObjetoGenerico>
{
    ObjetoGenerico Clonar();
}
## 2 - interface que define nosso objeto concreto
interface IFulano : IPrototipo<IFulano>
{
    string Beltrano;
    void Imprimir();
}

## 3 - nosso objeto concreto propriamente dito
public class Fulano : IFulano
{
    public string Beltrano;
    ## atributo/campo privado, que restringe o acesso
    ## podendo ser acessado apenas dentro da própria classe Fulano
    private string Siclano;

    public Fulano(string beltrano, string siclano)
    {
        this.Beltrano = beltrano;
        this.Siclano = siclano;
    }
    public void Imprimir()
    {
        Print($"\nBeltrano: {this.Beltrano}");
        Print($"\nSiclano: {this.Siclano}");
    }
    ## 4 - implementação do método de clonagem
    public IFulano Clonar()
    {
        ## observe que há um atributo/campo privado (Siclano) que não
        ## poderíamos acessar para fazer uma cópia do jeito convencional
        ## contudo, como estamos dentro do objeto, é permitido
        ## o acesso a seus atributos/campos privados
        return new Fulano(this.Beltrano, this.Siclano);
    }
}

```
Código do cliente definindo o objeto Fulano
e chamando o MétodoExemplo
```
var objetoOriginal = new Fulano("Jesse", "Feitoza");
MetodoExemplo(objetoOriginal);
```

Método em algum lugar do nosso código aceitando apenas
a interface do objeto Fulano
```
void MetodoExemplo(IFulano obj)
{
    var objetoClonado = obj.Clonar();
    objetoClonado.Beltrano = "Max";
    objetoClonado.Imprimir();
}
```