1. **Fonte:** Adaptado do Curso de Design Patterns com C# - Desenvolvimento Avançado https://www.udemy.com/course/curso-de-design-patterns-com-c-desenvolvimento-avancado **Projeto no GitHub:** https://github.com/felipemarchi/design-patterns-cs
2. Pilares da POO utilizados nos Padrões de Projetos
2.1. Abstração
2.2. Herança
2.3. Encapsulamento
2.4. Polimorfismo
3. Gang of Four
3.1. Classificação por Propósito
3.1.1. **Criacional (5)** *Programe para Interfaces e não para implementações *
3.1.1.1. Singleton
3.1.1.1.1. **Problema:** - Garantir somente uma instância do objeto - Reduzir o uso de memória - Melhorar o uso de soluções estáticas **Exemplo:** - Uma única bola num jogo de futebol **Implementação:** - Singleton não é a classe, mas sim o gerenciamento de sua instância - A classe Bola tem uma propriedade estática que sempre retorna a mesma instância da Bola **Na prática:** *var bola = Bola.RetornarInstancia; *
3.1.1.2. *Factory Method
3.1.1.2.1. **Problema:** - Existem vários tipos de objetos e não podemos antecipar a tomada de decisão - Delegar a responsabilidade de escolher um objeto para instanciar **Exemplo:** - Seleção de personagem no Mortal Kombat **Implementação:** - Factory Method pode ser considerado uma classe ou método - Existe uma interface comum entre os objetos (ex. IPersonagem) - Esta interface é o tipo de retorno do Factory Method - No entanto, um switch retorna as instâncias específicas (ex. return new SubZero();) **Na prática:** *var personagem = new FactoryMethod().EscolherPersonagem("SubZero"); *
3.1.1.3. Abstract Factory
3.1.1.3.1. **Problema:** - Eliminar a necessidade de anexar classes específicas no código (ex. CarroLuxo ao invés de Carro) - Flexibilizar a criação de classes e suas subclasses (ex. o CarroLuxo deve ter RodaLigaLeve ao invés de abstrair para Carro tem Roda) **Exemplo:** - Fábrica de carro (popular ou de luxo) **Implementação:** - Uma fábrica abstrata define o processo de construção dos objetos (ex. CarroFactory) - Fábricas concretas especificam o processo de construção (ex. CarroLuxoFactory) exigido pela classe abstrata - Abstract Factory pode ser considerado uma classe ou método - O mesmo switch do Factory Method, mas ao invés de retornar a instância diretamente, o case vai selecionar uma fabricação concreta que vai ajudar a criar a instância que será retornada **Na prática:** *var carro = new AbstractFactory().MontarCarro("luxo"); *
3.1.1.4. Builder
3.1.1.4.1. **Problema:** - Separar a construção de um objeto complexo de sua classe - Reaproveitar esse processo de construção para outras classes **Exemplo:** - Construção de um celular (Android ou iOS) **Implementação:** - O Construtor (interface) define um processo de construção em partes de um objeto - O construtor concreto especifica o processo de construção exigido pela interface - Builder pode ser considerado uma classe ou método - Desta vez não tem switch, uma vez que o método vai construir um objeto com a especificação solicitada **Na prática:** *var celular = new Builder().Construir(new AndroidBuilder()); *
3.1.1.5. Prototype
3.1.1.5.1. **Problema:** - Criar uma nova instância a partir de um objeto (clonar) **Exemplo:** - Podemos clonar classes específicas (ex. círculo, quadrado, retângulo) que herdam de uma entidade comum (ex. forma). A entidade comum que vai carregar a assinatura do método clone. **Implementação:** - A interface/classe abstrata obriga a implementação de um método clone - As classes que desejam ser protótipos, implementam/herdam da genérica - O método de clonagem retorna uma nova instância do objeto com suas propriedades atuais *this.memberWiseClone* (com cast para a interface!) **Na prática:** *var funcionarioClone = (Funcionario)funcionarioOriginal.Clone(); *
3.1.2. **Estrutural (7)** *Classes utilizam herança para compor interfaces e implementações. Objetos podem mudar sua composição dinamicamente. *
3.1.2.1. Adapter (2)
3.1.2.1.1. *Class Adapter
3.1.2.1.2. Object Adapter
3.1.2.1.3. **Problema:** - A atualização de uma API quebrou a comunicação com o sistema pois as interfaces agora são incompatíveis **Exemplo:** - Adaptador de tomada na vida real - Interface possui ações de um jogo (ex. atacar, defender e pular). A classe Personagem implementa a interface sem problemas, porém a classe Avião precisa ser adaptada (ex. atirar, desviar e voar) **Implementação:** - Objeto a ser adaptado | Classe Adapter | Interface alvo - O construtor do adapter recebe o objeto a ser adaptado - O adapter implementa a interface apontando para os métodos do objeto privado recebido **Na prática:** *var aviaoAdaptado = new AviaoAdapter(new Aviao()); * *aviaoAdaptado.pular(); *
3.1.2.2. Bridge
3.1.2.2.1. **Problema:** - Desacoplar especificações do conteúdo de uma classe - Permitir variar a especificação da classe ao instanciá-la **Exemplo:** - Televisão possui ICanal que pode ser qualquer canal (ex. CanalFilme, CanalDocumentario, CanalCulinaria) **Implementação:** - Uma classe independente possui uma propriedade do tipo de uma interface. Esta que pode ser instanciada como qualquer outro tipo (que respeite a interface) **Na prática:** *var tv = new Televisao() { Canal = new CanalFilme() }; *
3.1.2.3. Composite
3.1.2.3.1. **Problema:** - Estruturados objetos árvore para representar hierarquias **Exemplo:** - Sumário de um trabalho acadêmico **Implementação:** - Dois tipos de classe da estrutura (folha e composite) implementam a classe abstrata de um componente - Este componente define os métodos de adicionar, remover e mostrar filho **Na prática:** *var root = new Composite("ROOT"); * *root.adicionar(new Composite("Galho A")); * *root.adicionar(new Folha("Folha B")); *
3.1.2.4. Decorator
3.1.2.4.1. **Problema:** - Anexar nova funcionalidade dinamicamente - Nem todos as classes daquele conjunto deveriam ter a nova funcionalidade (ex. classe abstrata bebida: café pode ter condimentos como caramelo, já o chá não) **Exemplo:** - Adicionar condimentos em algumas classes derivada de Bebida **Implementação:** - Classe abstrata e seus herdeiros (ex. Bebida: café, chá) - DecoratorBebida herda de Bebida e recebe uma Bebida para decorar - Condimento herda do DecoratorBebida e além de incrementar os métodos que já existem (ex. getPreco) pode adicionar novos métodos (ex. adicionarCondimento("xpto") e listarCondimentosAdicionados()) **Na prática:** *Bebida cafe = new Cafe(); * *cafe.getPreco() // 2,00 * *Bebida cafeCaramelo= new Condimento(cafe, "caramelo"); * *cafeCaramelo.getPreco() // 3,50 *
3.1.2.5. Facade
3.1.2.5.1. **Problema:** - Fornecer uma interface unificada para um conjunto de interfaces em um subsistema - Facilitar e organizar a utilização de múltiplas classes uma vez que o Facade é uma interface de nível superior **Exemplo:** - Divisão de Cadastros (lembra um microservice) **Implementação:** - A classe Facade instancia todas as classes de um subsistema e invoca seus métodos na sequência que desejar **Na prática:** *var cadastro = new Cadastro(); * *cadastro.IncluirClienteNotificandoEmail(); *
3.1.2.6. Flyweight
3.1.2.6.1. **Problema:** - Necessidade de performance (rapidez e pouco consumo de memória) **Exemplo:** - Instanciar 1000 elementos (objetos) de um jogo é muito custoso - Cascos coloridos de tartarugas do super mario **Implementação:** - Classe abstrata define o objeto padrão (ex. casco) - Classes concretas herdeiras especificam o objeto (ex. cascoVermelho, cascoVerde) - A classe ou método Flyweight gerencia as intâncias já ocorridas (usar dicionário) **Na prática:** *var retorno = new Flyweight().getTartaruga("azul"); *
3.1.2.7. Proxy
3.1.2.7.1. **Problema:** - Controlar o acesso a um objeto **Exemplo:** - Proxies remotos organizam requisições externas - Proxies virtuais armazenam informações em cache - Proxies de proteção validam permissões de acesso **Implementação:** - Uma classe abstrata define o padrão para a classe concreta e o proxy - O proxy instancia (ou pega a instância existente) uma classe concreta e já invoca seu método de requisição **Na prática:** *var proxy = new Proxy().Requisicao(); *
3.1.3. **Comportamental (11)** *Classes utilizam herança para compartilhar comportamentos. Objetos utilizam a composição de objetos em contrapartida à herança *
3.1.3.1. Chain of Responsibility
3.1.3.1.1. **Problema:** - Maneira de passar uma requisição entre uma cadeia de objetos - Evita acoplamento entre solicitante e receptor, permitindo que mais objetos tenha acesso à requisição ao longo da cadeia **Exemplo:** - É preciso consumir uma lista de encomendas de forma a realizar uma ação diferente de acordo com cada statusEnvio do objeto **Implementação:** - Uma interface define classes concretas que podem ter sucessores - As classes podem ou não alterar o objeto da requisição de acordo com a condição **Na prática:** *var h1 = HandleRequest1(); * *var h2 = HandleRequest2(); * *var h3 = HandleRequest3(); * *h1.setSucessor(h2); * *h2.setSucessor(h3); * *foreach (item in list) { * * h1.Request(item); * *} *
3.1.3.2. Command
3.1.3.2.1. **Problema:** - Encapsular uma solicitação de comando como um objeto - Parametrizar, enfileirar, registrar e desfazer solicitações **Exemplo:** - É necessário emitir solicitações para objetos sem saber nada sobre a operação que está sendo solicitada ou o destinatário da solicitação. - Comando de um controle remoto. **Implementação:** - O Receiver é a classe com o método que faz a ação principal - Um Command concreto (que herda do abstrato) especifica as ações que vão executar o Receiver no final - O Command abstrato possui um Receiver e um método de ação - O Invoke tem um Command e vai ser utilizado pelo cliente **Na prática:** *var invoker = new Invoker(); * *invoker.setCommand(new ConcreteCommand(new Receiver())); * *invoker.executeCommand(); *
3.1.3.3. *Interpreter
3.1.3.3.1. **Problema:** - Maneira de incluir elementos de linguagem em um programa **Exemplo:** - Converter algarismos romanos em inteiro **Implementação:** - Contexto armazena propriedades globais para o Interpreter (ex. input e output) - Uma lista de objetos abstratos Expressao guarda todos os interpretadores concretos - Envio o contexto para cada interpretador das expressões **Na prática:** *foreach (Expressao exp in listaExpressoes) * * exp.Interpretar(contexto) *
3.1.3.4. Iterator
3.1.3.4.1. **Problema:** - Acessar elementos de uma coleção agregada sequencialmente **Exemplo:** - Classe para manipular listas sem expor suas representações; - Visitar roma (por conta, por aplicativo, por guia) **Implementação:** - Classes abstratas Aggregate e Iterator - As classes concretas, respectivamente, implementam a criação de um iterador concreto e o próprio iterador (First, Next, IsDone, CurrentItem) **Na prática:** *var iterator = aggregate.CreateIterartor(); * *var item = iterator.First(); * *while (item != null) { * * Console.WriteLine(item); * * item = iterator.Nex(); * *} *
3.1.3.5. Mediator
3.1.3.5.1. **Problema:** - Simplificar comunicação entre classes - Encapsular a interação entre um conjunto de objetos **Exemplo:** - Torre de controle de aeroporto **Implementação:** - Mediator (único) - Colleagues (diferentes tipos concretos) **Na prática:** *colega1.Enviar("Oi"); * A implementação de Enviar vai chamar o Enviar do mediador que vai notificar o "Oi" para o colega2
3.1.3.6. Memento
3.1.3.6.1. **Problema:** - Restaurar o estado interno de um objeto **Exemplo:** - Útil para funcionalidade "desfazer" ou quando utiliza-se transações **Implementação:** - Memento vai interagir com duas classes (Originador e Zelador) para armazenar o estado interno do objeto Originador - Originador cria uma lembrança e pode usá-la para restaurar seu estado - Zelador somente guarda e repassa uma lembrança **Na prática:** *var originator = new Originator("on"); * *var lembranca = originator.CriarMemento(); * *var zelador = new Caretaker(lembranca); * *originator.Status = "off"; * *originator.Restaurar(zelador.Memento); * No fim estado volta a ser "on"
3.1.3.7. Observer
3.1.3.7.1. **Problema:** - Notificar uma mudança de objeto para diversas classes (um para muitos) **Exemplo:** - Serviço de assinatura para ser notificado de algo novo sobre um determinado assunto/objeto **Implementação:** - Assunto anexa e desanexa seus observadores, e sua classe concreta implementa o envio da notificação quando seu estado muda - Observer armezena um assunto e implementa sua atualização - Ambos possuem classes abstratas **Na prática:** *var assunto = new AssuntoConcreto(); * *assunto.Anexar(new ObservadorConcreto("ob1", assunto)); * *assunto.Estado = "novoEstado"; * *assunto.Notificar(); * Tal que o Notificar vai chamar o Update de cada Observer da lista
3.1.3.8. State
3.1.3.8.1. **Problema:** - Alterar o comportamento de um objeto de acordo com seu estado **Exemplo:** - Comportamento dos botões de um celular de acordo com o estado do celular **Implementação:** - Contexto define uma interface para os clientes e armazena um estado atual concreto - Estado define uma interface para selecionar o comportamento - Cada estado concreto implementa um comportamento **Na prática:** *var contexto = new Context(new ConcreteStateA()); * *contexto.Request(); *
3.1.3.9. Strategy
3.1.3.9.1. **Problema:** - Encapsular uma família de algoritmos dentro de uma classe - Variar os algoritmos independentemente dos clientes que os usam **Exemplo:** - Estratégia de transporte até uma festa (bike, ônibus ou taxi) - Estratégia de ordenação de uma lista **Implementação:** - Estratégia é a interface usada pelo contexto para chamar uma estratégia - Cada classe concreta implementa uma estratégia - O contexto escolhe uma estratégia concreta, ao mesmo tempo em que disponibiliza uma interface para acesso aos seus dados **Na prática:** *var estudantes = new SortedList(); * *estudantes.Add("João"); * *estudantes.Add("Maria"); * *estudantes.SetSortStrategy(new QuickSort()); * *estudantes.Sort(); *
3.1.3.10. *Template Method
3.1.3.10.1. **Problema:** - Sobrescrever etapas específicas de uma algoritmo padrão de uma superclasse - Redefinir etapas de um processo sem alterar sua estrutura **Exemplo:** - Plano de arquitetura pode ser levemente alterado **Implementação:** - Classe abstrata define operações primitivas e ainda define um esqueleto de um algoritmo com essas operações - Classe concreta implementa as operações que precisam ser específica à subclasse **Na prática:** *AbstractClass processo = new ConcreteClassA(); * *processo.TemplateMethod(); * O TemplateMethod executa o processo padrão: PrimitiveOperation1 e PrimitiveOperation2
3.1.3.11. Visitor
3.1.3.11.1. **Problema:** - Definir uma nova operação para uma classe sem alteração - Operação a ser executada em objetos de uma estrutura que pode ser diferente sem alterar a classe **Exemplo:** - Agente de seguros vende diferentes coisas para cada estabelecimento que visita **Implementação:** - Visitor e Element (abstratos e concretos) - Elemento aceita um visitante, e cada visitante concreto implementa sua operação - Uma objectStruct ainda pode aumentar seus elementos e permite a visita dos visitantes. Pode ser um **Composite** ou uma coleção (ex. lista dos elementos) **Na prática:** *var lista = new ObjectStruct("casa", "prédio"); * *var visitante1 = new ConcreteVisitor1(); * *lista.Accept(visistante1); *
4. Extras
4.1. Dependency Injection
4.1.1. Por construtor
4.1.2. Por Getter e Setter
4.1.3. Por Implementação de Interface
4.1.4. Por Localizador de Serviço