├── LICENSE └── README.md /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright 2017 Kamran Ahmed 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 4 | 5 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 6 | 7 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 8 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ![Design Patterns For Humans](https://cloud.githubusercontent.com/assets/11269635/23065273/1b7e5938-f515-11e6-8dd3-d0d58de6bb9a.png) 2 | 3 | *** 4 |

5 | :tada: Explicação ultra-simplificada dos design patterns! :tada: 6 |

7 | 8 |

9 | Um assunto capaz de dar um nó na cabeça de qualquer um. Aqui eu tento fazê-los 10 | grudar na sua cabeça (e quem sabe na minha) explicando da maneira mais simples. 11 |

12 | 13 | *** 14 | 15 | :rocket: Introdução 16 | ================= 17 | 18 | Design patterns são soluções para problemas recorrentes; **guias de como atacar certos problemas**. 19 | Não são classes, pacotes nem bibliotecas que você bota na aplicação e espera a mágica acontecer. 20 | Na realidade, são guias de como atacar certos problemas em certas situações. 21 | 22 | > Design patterns solucionam problemas recorrentes; guias de como atacar certos problemas. 23 | 24 | A Wikipedia os descreve como 25 | 26 | > Em engenharia de software, um design pattern é uma solução geral reutilizável 27 | em problemas recorrentes dentro de um determinado contexto de design de software. 28 | Não é um design pronto, que pode ser transformado diretamente em código ou código de máquina. 29 | É uma descrição ou _template_ de como resolver um problema que pode ser utilizado 30 | em diversas situações diferentes. 31 | 32 | :warning: Cuidado 33 | ----------------- 34 | - Design patterns não são uma bala de prata para todos seus problemas 35 | - Não tente forçá-los; senão coisas ruins acontecerão. 36 | Tenha em mente que design patterns são soluções **para** problemas, 37 | e não soluções **para encontrar** problemas; então não pense demais. 38 | - Se for utilizado no local correto de maneira correta, eles podem se provar 39 | salvadores; senão eles podem acabar resultando numa bagunça de código horrorosa. 40 | 41 | Tipos de Design Patterns 42 | ----------------- 43 | 44 | * [De Criação](#design-patterns-de-criação) 45 | * [Estruturais](#design-patterns-estruturais) 46 | * [Comportamentais](#design-patterns-comportamentais) 47 | 48 | 49 | Design Patterns de Criação 50 | ========================== 51 | 52 | Resumindo 53 | > Padrões de criação focam em como instanciar um objeto ou grupo de objetos afins. 54 | 55 | A Wikipedia diz 56 | > Em engenharia de software, design patterns de criação são padrões que lidam 57 | com os mecanismos de criação de objetos, tentando criar os objetos de maneira 58 | adequada àquela situação. 59 | A forma basica de criação de objetos poderiam resultar em problemas de design 60 | ou adicionar complexidade ao design. 61 | Design patterns de criação resolvem este problema controlando a criação de objetos 62 | de alguma forma. 63 | 64 | * [Simple Factory](#-simple-factory) 65 | * [Factory Method](#-factory-method) 66 | * [Abstract Factory](#-abstract-factory) 67 | * [Builder](#-builder) 68 | * [Prototype](#-prototype) 69 | * [Singleton](#-singleton) 70 | 71 | 🏠 Simple Factory 72 | -------------- 73 | Exemplo do mundo real 74 | > Considere que você está construindo uma casa e que precise de portas. Seria uma bagunça se cada vez que você precisar de uma porta, você tenha que colocar suas roupas de carpinteiro e começar a cria-la em sua casa. Em vez disso você a obtém feita por uma fábrica. 75 | 76 | Resumindo 77 | > Simple factory simplesmente gera uma instância para o cliente sem expor qualquer lógica de instanciação para o cliente. 78 | 79 | Wikipedia diz 80 | > Na programação orientada a objetos (OOP), uma factory é um objeto para criar outros objetos - formalmente, uma factory é uma função ou método que retorna objetos de um protótipo ou classe variável de alguma chamada de método, que é assumida como "new". 81 | 82 | **Exemplo Programático** 83 | 84 | Primeiro, temos uma interface de porta e uma implementação 85 | ```csharp 86 | public interface IDoor 87 | { 88 | float Width { get; set; } 89 | float Height { get; set; } 90 | } 91 | 92 | public class WoodenDoor : IDoor 93 | { 94 | public float Width { get; set; } 95 | public float Height { get; set; } 96 | 97 | public WoodenDoor(float width, float height) 98 | { 99 | Width = width; 100 | Height = height; 101 | } 102 | } 103 | ``` 104 | Então nós temos nossa factory de porta, que faz a porta e retorna-a 105 | ```csharp 106 | class DoorFactory 107 | { 108 | public static IDoor MakeDoor(float width, float height) 109 | { 110 | return new WoodenDoor(width, height); 111 | } 112 | } 113 | ``` 114 | E então ele pode ser usado como 115 | ```csharp 116 | var door = DoorFactory.makeDoor(100, 200); 117 | Console.WriteLine("Width: " + door.Width); 118 | Console.WriteLine("Height: " + door.Height); 119 | ``` 120 | 121 | **Quando usar?** 122 | 123 | Ao criar um objeto que envolve alguma lógica e não apenas algumas atribuições, faz sentido colocá-lo em uma factory dedicada em vez de repetir o mesmo código em todos os lugares. 124 | 125 | 🏭 Factory Method 126 | -------------- 127 | 128 | Exemplo do mundo real 129 | > Considere o caso de um gerente de contratação. É impossível para apenas uma pessoa entrevistar candidatos para cada uma das posições. Com base na abertura do trabalho, ela tem que decidir e delegar as etapas da entrevista para diferentes pessoas. 130 | 131 | Resumindo 132 | > Ele fornece uma maneira de delegar a lógica de instanciação a classe filho. 133 | 134 | Wikipedia diz 135 | > Na programação baseada em classes, o padrão de método de factory é um padrão de criação que usa métodos de factory para lidar com o problema de criação de objetos sem precisar especificar a classe exata do objeto que será criado. Isso é feito criando objetos chamando um método de factory - ou especificado em uma interface e implementado por classe filho, ou implementado em uma classe base e opcionalmente substituído por classes derivadas - em vez de chamar um construtor. 136 | 137 | **Exemplo Programático** 138 | 139 | Tomando o nosso exemplo de gerente de contratação acima. Primeiro de tudo, temos uma interface de entrevistador e algumas implementações para ele 140 | 141 | ```csharp 142 | interface IInterviewer 143 | { 144 | void AskQuestions(); 145 | } 146 | 147 | class Developer : IInterviewer 148 | { 149 | public void AskQuestions() 150 | { 151 | Console.WriteLine("Asking about design patterns!"); 152 | } 153 | } 154 | 155 | class CommunityExecutive : IInterviewer 156 | { 157 | public void AskQuestions() 158 | { 159 | Console.WriteLine("Asking about community building"); 160 | } 161 | } 162 | ``` 163 | 164 | Agora vamos criar o nosso `HiringManager` 165 | 166 | ```csharp 167 | abstract class HiringManager 168 | { 169 | // Factory method 170 | public abstract IInterviewer MakeInterviewer(); 171 | 172 | public void TakeInterview() 173 | { 174 | var interviewer = MakeInterviewer(); 175 | interviewer.AskQuestions(); 176 | } 177 | } 178 | ``` 179 | Agora, qualquer filho pode estendê-lo e fornecer o entrevistador necessário 180 | ```csharp 181 | class DevelopmentManager : HiringManager 182 | { 183 | public IInterviewer MakeInterviewer() 184 | { 185 | return new Developer(); 186 | } 187 | } 188 | 189 | class MarketingManager : HiringManager 190 | { 191 | public IInterviewer MakeInterviewer() 192 | { 193 | return new CommunityExecutive(); 194 | } 195 | } 196 | ``` 197 | E então ele pode ser usado como 198 | 199 | ```csharp 200 | var devManager = new DevelopmentManager(); 201 | devManager.TakeInterview(); // Output: Asking about design patterns 202 | 203 | var marketingManager = new MarketingManager(); 204 | marketingManager.TakeInterview(); // Output: Asking about community building. 205 | ``` 206 | 207 | **Quando usar?** 208 | 209 | Útil quando há algum processamento genérico em uma classe, mas a sub-classe necessária é dinamicamente decidida em tempo de execução. Ou colocando em outras palavras, quando o cliente não sabe qual sub-classe exatamente precisará. 210 | 211 | 🔨 Abstract Factory 212 | ---------------- 213 | 214 | Exemplo do mundo real 215 | > Extenderemos o nosso exemplo sobre portas, visto no Simple Factory. Baseado em sua necessidade você pode obter uma porta de madeira de uma loja que vende portas de madeira, umaporta de ferro de uma loja que vende portas de ferro ou uma porta de PVC, se for a uma loja que venda porta deste tipo. Além disto, você precisará de uma pessoa com tipos diferentes de especializações para preparar cada porta.Por exemplo;um carpinteiro para portas de madeira, soldador para portas de ferro e etc. Como pode perceber, existem dependências entre portas, portas de madeira com carpinteiros e portas de ferro com soldador. 216 | 217 | 218 | Resumindo 219 | > Uma Factory de Factories; uma factory que agrupa outras factories com o seu relacionado/dependente sem especificar sua classe concreta. 220 | 221 | 222 | Wikipedia diz 223 | > O Abstract Factory Pattern provê uma maneira de encapsular um grupo de Factories que tem um tema em comum sem especificar suas classes concretas. 224 | 225 | **Exemplo Programático** 226 | 227 | Traduzindo o acima sobre as portas. Primeiro, temos nossa interface `Door` e algumas implementações dela. 228 | 229 | ```csharp 230 | interface IDoor 231 | { 232 | void GetDescription(); 233 | } 234 | 235 | class WoodenDoor : IDoor 236 | { 237 | public void GetDescription() 238 | { 239 | Console.WriteLine("I am a wooden door"); 240 | } 241 | } 242 | 243 | class IronDoor : IDoor 244 | { 245 | public void GetDescription() 246 | { 247 | Console.WriteLine("I am a iron door"); 248 | } 249 | } 250 | ``` 251 | Então, nós temos alguns especialistas em montagem para cada tipo de porta. 252 | 253 | ```csharp 254 | interface IDoorFittingExpert 255 | { 256 | void GetDescription(); 257 | } 258 | 259 | class Welder : IDoorFittingExpert 260 | { 261 | public void GetDescription() 262 | { 263 | Console.WriteLine("I can only fit iron doors"); 264 | } 265 | } 266 | 267 | class Carpenter : IDoorFittingExpert 268 | { 269 | public void GetDescription() 270 | { 271 | Console.WriteLine("I can only fit wooden doors"); 272 | } 273 | } 274 | ``` 275 | Agora, nós temos uma Factory abstrata que poderá nos deixa criar objetos relacionados a uma mesma família, por exemplo; uma Factory de portas de madeira criará uma porta de madeira e um especialista em montagem de portas de mandeira e a Factory de portas de metal criará uma porta de metal com um especialista em montagem de portas de metal. 276 | 277 | ```csharp 278 | interface IDoorFactory 279 | { 280 | IDoor MakeDoor(); 281 | IDoorFittingExpert MakeFittingExpert(); 282 | } 283 | 284 | // Factory de portas de madeira retorna carpinteiro e porta de madeira 285 | class WoodenDoorFactory : IDoorFactory 286 | { 287 | public IDoor MakeDoor() 288 | { 289 | return new WoodenDoor(); 290 | } 291 | 292 | public IDoorFittingExpert MakeFittingExpert() 293 | { 294 | return new Carpenter(); 295 | } 296 | } 297 | 298 | // Factory de portas de ferro retornará porta de ferro e um soldador 299 | class IronDoorFactory : IDoorFactory 300 | { 301 | public IDoor MakeDoor() 302 | { 303 | return new IronDoor(); 304 | } 305 | 306 | public IDoorFittingExpert MakeFittingExpert() 307 | { 308 | return new Welder(); 309 | } 310 | } 311 | ``` 312 | E poderá ser usado desta maneira 313 | ```csharp 314 | var woodenFactory = new WoodenDoorFactory(); 315 | 316 | var door = woodenFactory.MakeDoor(); 317 | var expert = woodenFactory.MakeFittingExpert(); 318 | 319 | door.GetDescription(); // Output: I am a wooden door 320 | expert.GetDescription(); // Output: I can only fit wooden doors 321 | 322 | // Same for Iron Factory 323 | var ironFactory = new IronDoorFactory(); 324 | 325 | var door = ironFactory.MakeDoor(); 326 | var expert = ironFactory.MakeFittingExpert(); 327 | 328 | door.GetDescription(); // Output: I am an iron door 329 | expert.GetDescription(); // Output: I can only fit iron doors 330 | ``` 331 | 332 | Como pode reparar, a Factory de porta de madeira encapsula o `carpinteiro` e a `porta de madeira` e a Factory de porta de ferro encapsula o `soldador` e a `porta de ferro`. E com isto nos ajuda a ter certeza que para cada porta criada nós não tenhamos um especialista em montagem errado. 333 | 334 | 335 | **Quando usar?** 336 | 337 | Quado existir uma interralação de dependencia com uma lógica de criação não tão simples. 338 | 339 | 👷 Builder 340 | -------------------------------------------- 341 | Exemplo do mundo real 342 | > Imagine que você está no McDonald's e pede uma oferta em específico, diríamos, "Big Mac" e eles te entregam o 343 | sanduíche *sem nenhuma pergunta*; isto é um exemplo de uma simples fábrica. 344 | Mas existem alguns casos em que a lógica de criação pode envolver mais passos. 345 | Por exemplo, você quer uma oferta do Subway personalizada, você tem várias opções em como seu sanduíche é feito, 346 | por exemplo, que pão você quer? Quais tipos de molho você quer? Qual queijo? etc. 347 | Nesses casos o padrão builder vem ao resgate. 348 | 349 | Resumindo 350 | > Permite que você crie diferentes variedades de um objeto enquanto evita poluição do construtor. 351 | Útil quando poderia haver diversas variedades de um objeto. 352 | Ou quando há muitos passos envolvida na criação de um objeto. 353 | 354 | Wikipedia diz 355 | > O padrão Builder é um design pattern de criação com a intenção de encontrar a solução 356 | anti-pattern "constructor telescoping". 357 | 358 | Tendo dito isto, permita-me adicionar um pouco sobre o que é o anti-pattern "tesleslcoping constructor". 359 | Em um momento ou outro todos nós já vimos um construtor como este abaixo: 360 | 361 | ```csharp 362 | public Burger(size, cheese = true, pepperoni = true, tomato = false, lettuce = true) 363 | { 364 | } 365 | ``` 366 | 367 | Como você pode notar; o número de parâmetros do construtor pode sair de controle rapidamente e pode ficar 368 | complicado entender a ordem dos parâmetros. E mais, esta lista de parâmetros poderia continuar crescendo caso 369 | queira adicionar mais opções no futuro. Isto é chamado de anti-pattern "telescoping constructor". 370 | 371 | 372 | **Exemplo Programático** 373 | 374 | A alternativa sensata é utilizar o padrão Builder. Antes de mais nada temos o sanduíche que queremos fazer 375 | 376 | ```csharp 377 | class Burger 378 | { 379 | public int Size { get; } 380 | 381 | public bool Cheese { get; } 382 | public bool Pepperoni { get; } 383 | public bool Lettuce { get; } 384 | public bool Tomato { get; } 385 | 386 | public Burger(BurgerBuilder builder) 387 | { 388 | Size = builder.Size; 389 | Cheese = builder.Cheese; 390 | Pepperoni = builder.Pepperoni; 391 | Lettuce = builder.Lettuce; 392 | Tomato = builder.Tomato; 393 | } 394 | } 395 | ``` 396 | 397 | E então temos o builder 398 | 399 | 400 | ```csharp 401 | class BurgerBuilder 402 | { 403 | public int Size { get; } 404 | 405 | public bool Cheese { get; private set; } 406 | public bool Pepperoni { get; private set; } 407 | public bool Lettuce { get; private set; } 408 | public bool Tomato { get; private set; } 409 | 410 | public BurgerBuilder(int size) 411 | { 412 | Size = size; 413 | } 414 | 415 | public BurgerBuilder AddPepperoni() 416 | { 417 | Pepperoni = true; 418 | return this; 419 | } 420 | 421 | public BurgerBuilder AddLettuce() 422 | { 423 | Lettuce = true; 424 | return this; 425 | } 426 | 427 | public BurgerBuilder AddCheese() 428 | { 429 | Cheese = true; 430 | return this; 431 | } 432 | 433 | public BurgerBuilder AddTomato() 434 | { 435 | Tomato = true; 436 | return this; 437 | } 438 | 439 | public Burger Build() 440 | { 441 | return new Burger(this); 442 | } 443 | } 444 | ``` 445 | E então pode ser utilizado como: 446 | 447 | ```csharp 448 | var burger = new BurgerBuilder(14) 449 | .AddPepperoni() 450 | .AddLettuce() 451 | .AddTomato() 452 | .Build(); 453 | ``` 454 | 455 | **Quando utilizar?** 456 | 457 | Quando poderia haver diversas variedades de um objeto e para evitar "constructor telescoping". 458 | A diferença chave para o padrão factory é que; o padrão factory é utilizado quando o processo de criação é feito num 459 | único passo, enquanto o padrão builder é utilizado quando a criação é um processo que envolvem vários passos. 460 | 461 | 🐑 Prototype 462 | ------------ 463 | Exemplo do mundo real 464 | 465 | > Lembra da dolly? A ovelha que foi clonada! Não vamos entrar nos detalhes mas o ponto chave aqui é que é tudo sobre 466 | clonagem. 467 | 468 | Resumindo 469 | > Criar objetos baseado num existente através de clonagem. 470 | 471 | 472 | Wikipedia diz 473 | > O padrão prototype é um padrão criacional no desenvolvimento de software. 474 | Ele é utilizado quando o tipo do objeto a ser criado é determinada por uma instancia prototipada, a qual é clonada 475 | para produzir novos objetos. 476 | 477 | Ou seja, ela te permite criar uma cópia de um objeto existente e modificá-lo de acordo com suas necessidades, 478 | ao invés de ter que passar por toda dificuldade de criar um objeto do zero e configurá-lo. 479 | 480 | **Exemplo programático** 481 | 482 | Em C#, isto pode ser facilmente feito utilizando `ICloneable` 483 | 484 | ```csharp 485 | class Sheep : ICloneable 486 | { 487 | public string Name { get; set; } 488 | public string Category { get; set; } 489 | 490 | public Sheep(string name, string category = "Mountain Sheep") 491 | { 492 | Name = name; 493 | Category = category; 494 | } 495 | 496 | public object Clone() 497 | { 498 | return this.MemberwiseClone(); 499 | } 500 | } 501 | ``` 502 | Então ele pode ser clonado assim 503 | ```csharp 504 | var original = new Sheep('Jolly', 'Mountain Sheep'); 505 | Console.WriteLine(original.Name); // Jolly 506 | Console.WriteLine(original.Category); // Mountain Sheep 507 | 508 | // Clone and modify what is required 509 | var cloned = original.Clone(); 510 | cloned.Name = "Dolly"; 511 | Console.WriteLine(cloned.Name); // Dolly 512 | Console.WriteLine(cloned.Category); // Mountain Sheep 513 | ``` 514 | 515 | Você também poderia utilizar o método mágico `Clone` e modificar o comportamente de clonagem. 516 | 517 | **Quando utilizar?** 518 | 519 | Quando um objeto requer que seja similar a um objeto similar existente ou quando a criação seria cara demais 520 | se comparada com a clonagem. 521 | 522 | 523 | 💍 Singleton 524 | ------------ 525 | Exemplo do mundo real 526 | > Só pode haver um presidente de um pais por vez. O mesmo presidente entra em ação quando o dever chama. 527 | Presidente aqui é um singleton. 528 | 529 | Resumindo 530 | > Garante que apenas um objeto de uma determinada classe será criado. 531 | 532 | Wikpedia diz 533 | > Em engenharia de software, o padrão singleton é um padrão de projeto que restringe a instanciação de uma classe 534 | para um único objeto. Isto é útil quando exatamente um objeto é necessário para coordenar ações por todo o sistema. 535 | 536 | O padrão singleton na realidade é considerado um anti-pattern e deve-se evitar usá-lo demais. 537 | Não é necessariamente ruim e pode haver alguns casos válidos mas deve ser utilizado com cuiidado pois introduz 538 | um estado global à sua aplicação e mudanças em um lugar pode ocasionar efeitos em outras areas e pode acabar 539 | se tornando bem difícil de debugar. 540 | A outra coisa ruim sobre ele é que torna seu código fortemente acoplado, em mais, mockar um singleton pode ser difícil. 541 | 542 | **Exemplo Programático** 543 | 544 | Para criar um singleton, faça o construtor privado, desabilite clonagem, desabilite extensão e crie uma variável estática para instancias de casa. 545 | 546 | ```csharp 547 | // Example taken from http://csharpindepth.com/Articles/General/Singleton.aspx 548 | // There is a lot of caveat. So read it! 549 | public sealed class President 550 | { 551 | private static readonly President instance = new President(); 552 | 553 | // Explicit static constructor to tell C# compiler 554 | // not to mark type as beforefieldinit 555 | static President() 556 | { 557 | } 558 | 559 | private President() 560 | { 561 | } 562 | 563 | public static President Instance 564 | { 565 | get 566 | { 567 | return instance; 568 | } 569 | } 570 | } 571 | ``` 572 | Então para utilizar 573 | ```csharp 574 | var president1 = President.Instance; 575 | var president2 = President.Instance; 576 | 577 | Console.WriteLine(President1 == President2); // true 578 | ``` 579 | 580 | Design Patterns Estruturais 581 | ========================== 582 | 583 | Resumindo 584 | > Padrões estruturais basicamente se preocupam com a composição de objetos 585 | ou em outras palavras como entidades usam umas às outras. 586 | Ou ainda outra explicação seria como elas ajudam a responder "Como construir 587 | um componente de software?". 588 | 589 | A Wikipedia diz 590 | > Em engenharia de software, design patterns estruturais são padrões que facilitam 591 | o design através da identificação de uma maneira simples de construir as relações entre as 592 | entidades. 593 | 594 | * [Adapter](#-adapter) 595 | * [Bridge](#-bridge) 596 | * [Composite](#-composite) 597 | * [Decorator](#-decorator) 598 | * [Facade](#-facade) 599 | * [Flyweight](#-flyweight) 600 | * [Proxy](#-proxy) 601 | 602 | 🔌 Adapter 603 | ------- 604 | Exemplo do mundo real 605 | > Considere que você tem algumas fotos em seu cartão de memória e que você precisa transferi-los para o seu computador. E para transferi-los você precisa de algum tipo de adaptador que seja compatível com as portas do computador. Neste caso o leitor de cartões é um adaptador. 606 | > Outro exemplo seria o famoso adaptador de alimentação; Um plugue de três pernas não pode ser conectado a uma saída de duas pontas, ele precisa usar um adaptador de energia que torna compatível com a saída de duas pontas. 607 | > Outro exemplo seria um tradutor traduzindo palavras ditas por uma pessoa a outra. 608 | 609 | Resumindo 610 | > O padrão Adapter permite que você envolva um objeto incompatível em um adaptador para torná-lo compatível com outra classe. 611 | 612 | A Wikipidia diz 613 | > Na engenharia de software, o padrão do Adapter é um padrão de design de software que permite que a interface de uma classe existente seja usada como outra interface. É freqüentemente usado para fazer com que as classes existentes trabalhem com outras sem modificar seu código-fonte. 614 | 615 | **Exemplo Programático** 616 | 617 | Considere um jogo onde há um caçador e ele caça leões. 618 | 619 | Primeiro temos uma interface `Lion` que todos os tipos de leões têm que implementar. 620 | 621 | ```csharp 622 | interface ILion 623 | { 624 | void Roar(); 625 | } 626 | 627 | class AfricanLion : ILion 628 | { 629 | public void Roar() {} 630 | } 631 | 632 | class AsianLion : ILion 633 | { 634 | public void Roar() {} 635 | } 636 | ``` 637 | E o caçador espera que qualquer implementação da interface `ILion` para caçar. 638 | ```csharp 639 | class Hunter 640 | { 641 | public void Hunt(ILion lion) 642 | { 643 | } 644 | } 645 | ``` 646 | 647 | Agora vamos dizer que temos de adicionar um `WildDog` no nosso jogo para que o caçador possa caçar isso também. Mas não podemos fazer isso diretamente porque o cão tem uma interface diferente. Para torná-lo compatível para o nosso caçador, vamos ter que criar um adaptador compatível. 648 | 649 | ```csharp 650 | // Isso precisa ser adicionado ao jogo 651 | class WildDog 652 | { 653 | public void Bark() {} 654 | } 655 | 656 | // Adaptador em torno do cão selvagem para torná-lo compatível com o nosso jogo 657 | class WildDogAdapter : ILion 658 | { 659 | private WildDog Dog { get; set; } 660 | 661 | public WildDogAdapter(WildDog dog) 662 | { 663 | Dog = dog; 664 | } 665 | 666 | public void Roar() 667 | { 668 | Dog.Bark(); 669 | } 670 | } 671 | ``` 672 | E agora o `WildDog` pode ser usado em nosso jogo usando` WildDogAdapter`. 673 | 674 | ```csharp 675 | var wildDog = new WildDog(); 676 | var wildDogAdapter = new WildDogAdapter(wildDog); 677 | 678 | var hunter = new Hunter(); 679 | hunter.Hunt(wildDogAdapter); 680 | ``` 681 | 682 | 🚡 Bridge 683 | ------ 684 | Exemplo do mundo real 685 | > 686 | Considere que você tem um site com páginas diferentes e supostamente o usuário pode alterar o tema. O que você faria? Criaria várias cópias de cada uma das páginas para cada um dos temas ou você apenas criaria o tema separado e carregar com base nas preferências do usuário? Bridge permite que você faça a segunda opção. 687 | 688 | ![Com e sem o Bridge](https://cloud.githubusercontent.com/assets/11269635/23065293/33b7aea0-f515-11e6-983f-98823c9845ee.png) 689 | 690 | Resumindo 691 | > Bridge pattern é sobre preferir a composição sobre herança. Detalhes de implementação são empurrados de uma hierarquia, para outro objeto com uma hierarquia separada. 692 | 693 | Wikipedia diz 694 | > O bridge é um padrão de projeto usado na engenharia de software que destina-se a "desacoplar uma abstração de sua implementação para que os dois possam variar independentemente". 695 | 696 | **Exemplo Programático** 697 | 698 | Traduzindo nosso exemplo de WebPage acima. Aqui temos a hierarquia `IWebPage` 699 | 700 | ```csharp 701 | interface IWebPage 702 | { 703 | string GetContent(); 704 | } 705 | 706 | class About : IWebPage 707 | { 708 | private ITheme Theme { get; set; } 709 | 710 | public About(ITheme theme) 711 | { 712 | Theme = theme; 713 | } 714 | 715 | public string GetContent() 716 | { 717 | return "About page in " + Theme.GetColor(); 718 | } 719 | } 720 | 721 | class Careers : IWebPage 722 | { 723 | private ITheme Theme { get; set; } 724 | 725 | public Careers(ITheme theme) 726 | { 727 | Theme = theme; 728 | } 729 | 730 | public string GetContent() 731 | { 732 | return "Careers page in " + Theme.GetColor(); 733 | } 734 | } 735 | ``` 736 | E a hierarquia de tema separada 737 | ```csharp 738 | interface ITheme 739 | { 740 | string GetColor(); 741 | } 742 | 743 | class DarkTheme : ITheme 744 | { 745 | public string GetColor() 746 | { 747 | return "Dark Black"; 748 | } 749 | } 750 | class LightTheme : ITheme 751 | { 752 | public string getColor() 753 | { 754 | return "Off white"; 755 | } 756 | } 757 | class AquaTheme : ITheme 758 | { 759 | public string GetColor() 760 | { 761 | return "Light blue"; 762 | } 763 | } 764 | ``` 765 | E ambas as hierarquias 766 | ```csharp 767 | var darkTheme = new DarkTheme(); 768 | 769 | var about = new About(darkTheme); 770 | var careers = new Careers(darkTheme); 771 | 772 | Console.WriteLine(about.GetContent()); // "About page in Dark Black"; 773 | Console.WriteLine(careers.GetContent()); // "Careers page in Dark Black"; 774 | ``` 775 | 776 | 🌿 Composite 777 | ----------------- 778 | 779 | Exemplo do mundo real 780 | > Toda organização é composta por empregados. Cada um dos empregados possuirá as mesmas caracteristicas, tais como salário, possui responsabilidades, pode ou não ter que se reportar a algém ou pode ou não ter subordinados. 781 | 782 | Resumindo 783 | > Composite Pattern deixa o cliente tratar objetos individuais de maneira uniforme. 784 | 785 | Wikipedia diz 786 | > Em engenharia de software, o Composite Patter é um design pattern de particionamento. O Composite Pattern descreve que um grupo de objetos deverá ser tratado da mesma maneira que apenas uma instancia de um objeto. A intensão de um Composite é "compor" objetos em estrutura de arvore representando parte de uma hierarquia. Implementar o Composite Patter é permitir que clientes tratem objetos individuais e composições de maneira uniforme. 787 | 788 | **Exemplo programático** 789 | 790 | Usaremos nosso exemplo acima com funcionários. Temos diferentes tipos de funcionários. 791 | 792 | ```csharp 793 | interface IEmployee 794 | { 795 | string Name { get; } 796 | float Salary { get; set; } 797 | IEmployee[] Roles { get; } 798 | } 799 | 800 | class Developer : IEmployee 801 | { 802 | public float Salary { get; set; } 803 | public string Name { get; } 804 | public IEmployee[] Roles { get; } 805 | 806 | public Developer(string name, float salary) 807 | { 808 | Name = name; 809 | Salary = salary; 810 | } 811 | } 812 | 813 | class Designer : IEmployee 814 | { 815 | public float Salary { get; set; } 816 | public string Name { get; } 817 | public IEmployee[] Roles { get; } 818 | 819 | public Designer(string name, float salary) 820 | { 821 | Name = name; 822 | Salary = salary; 823 | } 824 | } 825 | ``` 826 | 827 | Então, temos uma organização que é composta por inumero tipos diferentes de funcionários. 828 | 829 | ```csharp 830 | class Organization 831 | { 832 | private IList Employees { get; } = new List(); 833 | 834 | public void AddEmployee(IEmployee employee) 835 | { 836 | Employees.Add(employee); 837 | } 838 | 839 | public float GetNetSalaries() => Employees.Sum(employee => employee.Salary); 840 | } 841 | ``` 842 | 843 | E ele pode ser usado como. 844 | 845 | ```csharp 846 | // Prepara os funcionários 847 | var john = new Developer("John Doe", 12000); 848 | var jane = new Designer("Jane", 10000); 849 | 850 | // Adicione-os à organização 851 | organization = new Organization(); 852 | organization.AddEmployee(john); 853 | organization-.AddEmployee(jane); 854 | 855 | Console.WriteLine("Net salaries: " + organization.GetNetSalaries()); // Net Salaries: 22000 856 | ``` 857 | 858 | ☕ Decorator 859 | ------------- 860 | 861 | Exemplo do mundo real 862 | 863 | > Imagine você gerenciando uma oficina de carro com muitos serviços. Agora, como você calcularia a conta a ser cobrada? Você escolhe um serviço e começa a adicionar a este serviço preços por demais serviços prestados, de maneira dinâmica, até você ter o custo total final. Aqui que cada um destes serviços seria um decorator. 864 | 865 | Resumindo 866 | > Decorator Pattern permite que você altere o comportamento de um objeto em tempo de execução, envolvendo-o por um objeto de uma classe Decorator. 867 | 868 | Wikipedia diz 869 | > Em programação orientada a objeto, o Decorator Pattern permite que se adicione comportamentos para um objeto, tanto de maneira estatica quanto dinâmica, sem afetar o comportamento de outros objetos da mesma classe. O Decorator Pattern é muito útil para ser aderente ao principio de responsabilidade única, uma vez que ele permite que funcionalidades sejam divididas entre classes que compartilhe uma única preocupação. 870 | 871 | **Exemplo programático** 872 | 873 | Vamos pegar o café como exemplo. Primero de tudo, nós temos um simples café implementando a interface café. 874 | ```csharp 875 | interface ICoffee 876 | { 877 | int Cost { get; } 878 | string Description { get; } 879 | } 880 | 881 | class SimpleCoffee : ICoffee 882 | { 883 | public int Cost { get; } = 10; 884 | public string Description { get; } = "Simple coffee"; 885 | } 886 | ``` 887 | Nós queremos deixar o código extensivel para permitir opções de modificação caso seja necessário. Vamos fazer alguns complementos(Decorators). 888 | ```csharp 889 | class MilkCoffee : ICoffee 890 | { 891 | protected ICoffee Coffee { get; } 892 | 893 | public int Cost { get { return Coffee.Cost + 2; } } 894 | 895 | public string Description { get { return Coffee.Description + ", milk"; } } 896 | 897 | public MilkCoffee(ICoffee coffee) 898 | { 899 | Coffee = coffee; 900 | } 901 | } 902 | 903 | class WhipCoffee : ICoffee 904 | { 905 | protected ICoffee Coffee { get; } 906 | 907 | public int Cost { get { return Coffee.Cost + 5; } } 908 | 909 | public string Description { get { return Coffee.Description + ", whip"; } } 910 | 911 | public WhipCoffee(ICoffee coffee) 912 | { 913 | Coffee = coffee; 914 | } 915 | } 916 | 917 | class VanillaCoffee : ICoffee 918 | { 919 | protected ICoffee Coffee { get; } 920 | 921 | public int Cost { get { return Coffee.Cost + 3; } } 922 | 923 | public string Description { get { return Coffee.Description + ", vanilla"; } } 924 | 925 | public VanillaCoffee(ICoffee coffee) 926 | { 927 | Coffee = coffee; 928 | } 929 | } 930 | ``` 931 | Vamos fazer um café agora! 932 | ```csharp 933 | var someCoffee = new SimpleCoffee(); 934 | Console.WriteLine(someCoffee.Cost()); // 10 935 | Console.WriteLine(someCoffee.Description()); // Simple Coffee 936 | 937 | someCoffee = new MilkCoffee(someCoffee); 938 | Console.WriteLine(someCoffee.Cost()); // 12 939 | Console.WriteLine(someCoffee.Description(); // Simple Coffee, milk 940 | 941 | someCoffee = new WhipCoffee(someCoffee); 942 | Console.WriteLine(someCoffee.Cost()); // 17 943 | Console.WriteLine(someCoffee.Description()); // Simple Coffee, milk, whip 944 | 945 | someCoffee = new VanillaCoffee($someCoffee); 946 | Console.WriteLine(someCoffee.Cost()); // 20 947 | Console.WriteLine(someCoffee.Description()); // Simple Coffee, milk, whip, vanilla 948 | ``` 949 | 950 | 📦 Facade 951 | ---------------- 952 | 953 | Exemplo do mundo real 954 | > Como voce liga seu compudator? "Aperto o botão ligar", você diz! Isto é o que você pensa, já que está utilizando uma simples interface exposta pelo computador. Internamente ele faz muitas coisas para que o "ligar" ocorra. Esta interface simples para um subsistema complexo é o Facade. 955 | 956 | Resumindo 957 | > O Pattern Facade provê uma interface simples para um subsistema complexo. 958 | 959 | Wikipedia diz 960 | > Uma Facade é um objeto que provê uma interface simples para uma grande porção de código como uma Class Library. 961 | 962 | **Exemplo programatico** 963 | Usando o exemplo sobre o computador acima, vamos criar uma classe para representa-la. 964 | 965 | ```csharp 966 | class Computer 967 | { 968 | public void GetElectricShock() 969 | { 970 | Console.WriteLine("Ouch!"); 971 | } 972 | 973 | public void MakeSound() 974 | { 975 | Console.WriteLine("Beep beep!"); 976 | } 977 | 978 | public void ShowLoadingScreen() 979 | { 980 | Console.WriteLine("Loading.."); 981 | } 982 | 983 | public void Bam() 984 | { 985 | Console.WriteLine("Ready to be used!"); 986 | } 987 | 988 | public void CloseEverything() 989 | { 990 | Console.WriteLine("Bup bup bup buzzzz!"); 991 | } 992 | 993 | public void Sooth() 994 | { 995 | Console.WriteLine("Zzzzz"); 996 | } 997 | 998 | public void PullCurrent() 999 | { 1000 | Console.WriteLine("Haaah!"); 1001 | } 1002 | } 1003 | ``` 1004 | Aqui temos uma Facade 1005 | ```csharp 1006 | class ComputerFacade 1007 | { 1008 | protected Computer Computer; 1009 | 1010 | public ComputerFacade(Computer computer) 1011 | { 1012 | Computer = computer; 1013 | } 1014 | 1015 | public void TurnOn() 1016 | { 1017 | Computer.GetElectricShock(); 1018 | Computer.MakeSound(); 1019 | Computer.ShowLoadingScreen(); 1020 | Computer.Bam(); 1021 | } 1022 | 1023 | public void TurnOff() 1024 | { 1025 | Computer.CloseEverything(); 1026 | Computer.PullCurrent(); 1027 | Computer.Sooth(); 1028 | } 1029 | } 1030 | ``` 1031 | Como usar a classe Facade. 1032 | ```csharp 1033 | var computer = new ComputerFacade(new Computer()); 1034 | computer.TurnOn(); // Ouch! Beep beep! Loading.. Ready to be used! 1035 | computer.TurnOff(); // Bup bup buzzz! Haah! Zzzzz 1036 | ``` 1037 | 1038 | 🍃 Flyweight 1039 | --------- 1040 | 1041 | Exemplo do mundo real 1042 | > Você já tomou chá fresco de alguma barraca? Eles geralmente fazem mais que um copo que você solicitou e guardam o que restou para servir a outro cliente que também solicitar, assim economizam recursos, como por exemplo gás. Flyweight Patter é sobre isto: compartilhar. 1043 | 1044 | 1045 | Resumindo 1046 | > Ele é usado para minimizar o uso de memoria ou gasto computacional, compartilhando o máximo que der com objetos semelhantes. 1047 | 1048 | 1049 | O Wikipedia diz 1050 | > Em programa de computadores, Flyweight é um padrão de design de software. Um Flyweight Pattern é um objeto que minimiza o uso de memória, compartilhando o máximo possível de indormações com objetos similares; Esta é uma maneira de usar objetos em larga escala quando uma simples representação repedida poderia usar uma iniceitavel quantidade de memória. 1051 | 1052 | **Exemplo programatico** 1053 | Traduzindo o nosso exemplo acima sobre o chá. Primeiro de tudo, temos tipos de chá e preparadores de chá. 1054 | 1055 | ```csharp 1056 | // Quanquer coisa que for cacheada é Flyweight 1057 | // Tipos de chá será Flyweight 1058 | class KarakTea 1059 | { 1060 | } 1061 | 1062 | // Atua como uma factory e salva os chás 1063 | class TeaMaker 1064 | { 1065 | protected Dictionary AvailableTea = new Dictionary(); 1066 | 1067 | public KarakTea Make(string preference) 1068 | { 1069 | if (!AvailableTea.Keys.Contains(preference)) 1070 | { 1071 | AvailableTea.Add(preference, new KarakTea()); 1072 | } 1073 | 1074 | return AvailableTea[preference]; 1075 | } 1076 | } 1077 | ``` 1078 | Então, nós temos o 'TeaShop' o qual pega os pedidos e os serve 1079 | ```csharp 1080 | class TeaShop 1081 | { 1082 | protected Dictionary Orders = new Dictionary(); 1083 | protected TeaMaker TeaMaker; 1084 | 1085 | public TeaShop(TeaMaker teaMaker) 1086 | { 1087 | TeaMaker = teaMaker; 1088 | } 1089 | 1090 | public void TakeOrder(string teaType, int table) 1091 | { 1092 | Orders[table] = TeaMaker.Make(teaType); 1093 | } 1094 | 1095 | public void Serve() 1096 | { 1097 | foreach(var table in Orders.Select(order => order.Key)) 1098 | { 1099 | Console.WriteLine("Serving tea to table# " + table); 1100 | } 1101 | } 1102 | } 1103 | ``` 1104 | E isto pode ser usado como no caso a baixo 1105 | 1106 | ```csharp 1107 | var teaMaker = new TeaMaker(); 1108 | var shop = new TeaShop(teaMaker); 1109 | 1110 | shop.TakeOrder("less sugar", 1); 1111 | shop.TakeOrder("more milk", 2); 1112 | shop.TakeOrder("without sugar", 5); 1113 | 1114 | shop.Serve(); 1115 | // Servindo chá para a mesa #1 1116 | // Servindo chá para a mesa #2 1117 | // Servindo chá para a mesa #5 1118 | ``` 1119 | 1120 | 🎱 Proxy 1121 | ------------------- 1122 | Exemplo do mundo real 1123 | > Você já utilizou um cartão de acesso para passar por uma porta? Existem muitas opções para abrir uma porta, por exemplo, você poderia tanto usar um cartão de aecsso quanto apertar um botão para passar por sua segurança. A função principla desta porta é abrir, porém existe um proxy antes disto que adiciona outras funcionalidades. Deixe-me explicar melhor isto usando o exemplo em código a seguir. 1124 | 1125 | Resumindo 1126 | > Usando o Proxy Patter, uma classe irá representar a funcionalidade de outra classe. 1127 | 1128 | Wikipedia diz 1129 | > Um Proxy, de forma geral, é uma classe funcionando como uma interface para outra coisa. Um Proxy é um envolucro (wrapper) ou Agent Object que é chamado pelo cliente para acessar o objeto real por traz da cena. O uso de Proxy pode ser simplesmente para repassar para um objeto real ou então adicionar lógica a ele. Na lógica adicional que o Proxy pode adicionar temos por exemplo cache para operações que consomem muitos recursos. 1130 | 1131 | **Exemplo Programatico** 1132 | Tendo o exempo da porta a cima, primeiramnete precisaremos criar a interface de porta e implementa-la. 1133 | 1134 | ```csharp 1135 | interface IDoor 1136 | { 1137 | void Open(); 1138 | void Close(); 1139 | } 1140 | 1141 | class LabDoor : IDoor 1142 | { 1143 | public void Open() 1144 | { 1145 | Console.WriteLine("Opening lab door"); 1146 | } 1147 | 1148 | public void Close() 1149 | { 1150 | Console.WriteLine("Closing the lab door"); 1151 | } 1152 | } 1153 | ``` 1154 | Então, nós temos um Proxy para adicionar segurança a porta que quisermos. 1155 | ```csharp 1156 | class Security 1157 | { 1158 | protected IDoor Door; 1159 | 1160 | public Security(IDoor door) 1161 | { 1162 | Door = door; 1163 | } 1164 | 1165 | public void Open(string password) 1166 | { 1167 | if (Authenticate(password)) 1168 | { 1169 | Door.Open(); 1170 | } 1171 | else 1172 | { 1173 | Console.WriteLine("Big no! It ain't possible."); 1174 | } 1175 | } 1176 | 1177 | public bool Authenticate(string password) 1178 | { 1179 | return password == "$ecr@t"; 1180 | } 1181 | 1182 | public void Close() 1183 | { 1184 | Door.Close(); 1185 | } 1186 | } 1187 | ``` 1188 | E assim é como ele pode ser utilizado 1189 | ```csharp 1190 | var door = new Security(new LabDoor()); 1191 | door.Open("invalid"); // Big no! It ain't possible. 1192 | 1193 | door.Open("$ecr@t"); // Opening lab door 1194 | door.Close(); // Closing lab door 1195 | ``` 1196 | Outro exemplo que podemos ter com este Patter é a implementação de data-mapper. Por exemplo, recentemente criei um ODM (Object Data Mapper) para MopngoD usando este Pattern, onde escrevi um Proxy sobre as camadas de classes que utiizassem o comando mágico `__call()`. Todas as chamadas de métodos passam pelo Proxy e depois pelo original do Mongo e o resultado retornado é o mesmo para todos eles, menos para os metodos `find()`e `findOne()`, onde os dados foram mapeados para os seus respectivos objetos antes de serem retornados. 1197 | 1198 | 1199 | Design Patterns Comportamentais 1200 | ========================== 1201 | 1202 | Resumindo 1203 | > Está preocupado com a atribuição de responsabilidades entre os objetos. 1204 | O que diferencia com os padrões estruturais é que eles não especificam somente 1205 | a estrutura, mas também traçam os padrões para as passagem/comunicação de mensagens entre eles. 1206 | Em outras palavras, eles ajudam a responder "Como rodar um comportamento no componente de software?". 1207 | 1208 | A Wikipedia diz 1209 | > Em engenharia de software, design patterns comportamentais são padrões que 1210 | identificam padrões comuns de comunicação entre os objetos e concretizam este padrão. 1211 | Desta forma, estes padrões aumentam a flexibilidade em executar estas comunicações. 1212 | 1213 | * [Chain of Responsibility](#-chain-of-responsibility) 1214 | * [Command](#-command) 1215 | * [Iterator](#-iterator) 1216 | * [Mediator](#-mediator) 1217 | * [Memento](#-memento) 1218 | * [Observer](#-observer) 1219 | * [Visitor](#-visitor) 1220 | * [Strategy](#-strategy) 1221 | * [State](#-state) 1222 | * [Template Method](#-template-method) 1223 | 1224 | 🔗 Chain of Responsibility 1225 | ----------------------- 1226 | 1227 | Exemplo do mundo real 1228 | > Por exemplo, você possui três métodos de pagamento (`A`, `B` e `C`) configurados em sua conta. Cada um destes com uma quantia diferente; em `A` você tem R$100, Em `B` você tem R$300, Em `C` você tem R$1000, e a preferência para pagamentos é `A` ou então `B` ou então `C`. Você tenta comprar algo que custe R$210. Usando a Chain of Responsibility, primeiramente a conta `A` é verificada para saber se pode comprar, se sim a compra é feita e a cadeia é quebrada, caso contrario, a verificação continual até encontrar uma que seja possível utilizar. Aqui `A`, `B` e `C` são as ligações da cadeia e todo o fenomeno é a Chain of Responsibility. 1229 | 1230 | Resumindo 1231 | > Este Pattern ajuda a criar uma cadeia de objetos. Requer entradas de uma saída e lê objeto por objeto até encontrar um resultado adequado. 1232 | 1233 | Wikipedia diz 1234 | > Em orientação a objeto, o Pattern Chain of Responsibility é um desing que consiste de um fonte com objetos de comandos e uma série de objetos de processamento. Cada objeto de processamento contem uma lógica que define objetos de comando que ele pode realizar; O demais é passado para o proximo objeto da cadeia. 1235 | 1236 | **Exemplo programático** 1237 | Traduzindo noss exemplo a cima sobre contas. Primeiramente, temos uma conta base mantendo a lógica para a cadeia de contas juntas e algumas contas. 1238 | 1239 | ```php 1240 | abstract class Account { 1241 | protected $successor; 1242 | protected $balance; 1243 | 1244 | public function setNext(Account $account) { 1245 | $this->successor = $account; 1246 | } 1247 | 1248 | public function pay(float $amountToPay) { 1249 | if ($this->canPay($amountToPay)) { 1250 | echo sprintf('Paid %s using %s' . PHP_EOL, $amount, get_called_class()); 1251 | } else if ($this->successor) { 1252 | echo sprintf('Cannot pay using %s. Proceeding ..' . PHP_EOL, get_called_class()); 1253 | $this->successor->pay($amountToPay); 1254 | } else { 1255 | throw Exception('None of the accounts have enough balance'); 1256 | } 1257 | } 1258 | 1259 | public function canPay($amount) : bool { 1260 | return $this->balance <= $amount; 1261 | } 1262 | } 1263 | 1264 | class Bank extends Account { 1265 | protected $balance; 1266 | 1267 | public function __construct(float $balance) { 1268 | $this->$balance = $balance; 1269 | } 1270 | } 1271 | 1272 | class Paypal extends Account { 1273 | protected $balance; 1274 | 1275 | public function __construct(float $balance) { 1276 | $this->$balance = $balance; 1277 | } 1278 | } 1279 | 1280 | class Bitcoin extends Account { 1281 | protected $balance; 1282 | 1283 | public function __construct(float $balance) { 1284 | $this->$balance = $balance; 1285 | } 1286 | } 1287 | ``` 1288 | 1289 | Agora, vamos preparar a cadeia usando os linques definidos a cima (exemplo: Banco, Paypal e Bitcoin) 1290 | 1291 | ```php 1292 | // Let's prepare a chain like below 1293 | // $bank->$paypal->$bitcoin 1294 | // 1295 | // First priority bank 1296 | // If bank can't pay then paypal 1297 | // If paypal can't pay then bit coin 1298 | 1299 | $bank = new Bank(100); // Bank with balance 100 1300 | $paypal = new Paypal(200); // Paypal with balance 200 1301 | $bitcoin = new Bitcoin(300); // Bitcoin with balance 300 1302 | 1303 | $bank->setNext($paypal); 1304 | $paypal->setNext($bitcoin); 1305 | 1306 | // Let's try to pay using the first priority i.e. bank 1307 | $bank->pay(259); 1308 | 1309 | // Output will be 1310 | // ============== 1311 | // Cannot pay using bank. Proceeding .. 1312 | // Cannot pay using paypal. Proceeding ..: 1313 | // Paid 259 using Bitcoin! 1314 | ``` 1315 | 1316 | 👮 Command 1317 | ------- 1318 | 1319 | Exemplo do mundo real 1320 | > Um exemplo genérico seria você pedindo comida em um restaurante. Você (i.e. `Client`) pede ao garçon (i.e. `Invoker`) trazer comida (i.e. `Command`) e o garçon simplesmente leva seu pedido ao Chef (i.e. `Receiver`) que tem o conhecimento de o que e como cozinhar. 1321 | > Outro exemplo seria você (i.e. `Client`) ligando (i.e. `Command`) a televisão (i.e. `Receiver`) usando um controle remoto (`Invoker`). 1322 | 1323 | Resumindo 1324 | > O padrão Command permite que você encapsule ações em objetos. A ideia principal por trás desse padrão é prover os meios de desacoplar o cliente do receptor. 1325 | 1326 | A Wikipedia diz 1327 | > Na programação orientada a objeto, o padrão Command é um padrão de projeto comportamental no qual um objeto é usado para encapsular toda informação necessária para executar uma ação ou ativar um evento em um momento posterior. Esta informação inclui o nome do método, o objeto que possui o método e os valores para os parâmetros do método. 1328 | 1329 | **Exemplo Programático** 1330 | 1331 | Primeiramente, temos o receptor que tem a implementação de todas as ações que podem ser executadas. 1332 | ```php 1333 | // Receiver 1334 | class Bulb { 1335 | public function turnOn() { 1336 | echo "Bulb has been lit"; 1337 | } 1338 | 1339 | public function turnOff() { 1340 | echo "Darkness!"; 1341 | } 1342 | } 1343 | ``` 1344 | Então temos uma interface que cada um dos comandos vai implementar e em seguida, temos um conjunto de comandos. 1345 | ```php 1346 | interface Command { 1347 | public function execute(); 1348 | public function undo(); 1349 | public function redo(); 1350 | } 1351 | 1352 | // Command 1353 | class TurnOn implements Command { 1354 | protected $bulb; 1355 | 1356 | public function __construct(Bulb $bulb) { 1357 | $this->bulb = $bulb; 1358 | } 1359 | 1360 | public function execute() { 1361 | $this->bulb->turnOn(); 1362 | } 1363 | 1364 | public function undo() { 1365 | $this->bulb->turnOff(); 1366 | } 1367 | 1368 | public function redo() { 1369 | $this->execute(); 1370 | } 1371 | } 1372 | 1373 | class TurnOff implements Command { 1374 | protected $bulb; 1375 | 1376 | public function __construct(Bulb $bulb) { 1377 | $this->bulb = $bulb; 1378 | } 1379 | 1380 | public function execute() { 1381 | $this->bulb->turnOff(); 1382 | } 1383 | 1384 | public function undo() { 1385 | $this->bulb->turnOn(); 1386 | } 1387 | 1388 | public function redo() { 1389 | $this->execute(); 1390 | } 1391 | } 1392 | ``` 1393 | Então temos um `Invoker` com o qual o `Client` vai interagir para processar qualquer comando. 1394 | ```php 1395 | // Invoker 1396 | class RemoteControl { 1397 | 1398 | public function submit(Command $command) { 1399 | $command->execute(); 1400 | } 1401 | } 1402 | ``` 1403 | Finalmente, vamos ver como podemos usá-lo com o nosso `Client` 1404 | ```php 1405 | $bulb = new Bulb(); 1406 | 1407 | $turnOn = new TurnOn($bulb); 1408 | $turnOff = new TurnOff($bulb); 1409 | 1410 | $remote = new RemoteControl(); 1411 | $remoteControl->submit($turnOn); // Bulb has been lit! 1412 | $remoteControl->submit($turnOff); // Darkness! 1413 | ``` 1414 | 1415 | O padrão Command também pode ser utilizado para implementar um sistema baseado em transações onde você continua mantendo o histórico de comandos assim que você os executa. Se o comando final é executado com sucesso, tudo bem. Caso contrário, simplesmente itere sobre pelo histórico e execute o comando `undo` em todos os comandos executados. 1416 | 1417 | ➿ Iterator 1418 | -------- 1419 | 1420 | Exemplo do mundo real 1421 | > Um antigo aparelho de radio será um bom exemplo para iterador, onde o usuário começa em alguma estação e então usa os botões próximo ou anterior para navegar entre as demais. Ou use o exemplo de um MP3 player ou uma TV, onde você pode apertar os botões próximo e anterior para percorrer os canais em sequência, em outras palavras, todos eles fornecem uma interface para iterar através dos respectivos canais, músicas ou estações de rádio. 1422 | 1423 | 1424 | Resumindo 1425 | > Ele apresenta uma maneira de acessar os elementos de um objeto sem expor a toda a estrutura. 1426 | 1427 | Wikipedia diz 1428 | > Na programação orientada a objetos, um iterador se refere tanto ao objeto que permite ao programador percorrer um container, (uma coleção de elementos) particularmente listas,quanto ao design pattern Iterator, no qual um iterador é usado para percorrer um container e acessar seus elementos. O padrão Iterator desacopla os algoritmos dos recipientes, porém em alguns casos, os algoritmos são necessariamente específicos dos containers e, portanto, não podem ser desacoplados. 1429 | 1430 | **Exemplo Programático** 1431 | Com PHP é relativamente fácil implementar usando SPL (Biblioteca PHP Padrão). Traduzindo nosso exemplo das estações de rádio para o código abaixo. Primeiramente nós temos a 'EstacaoDeRadio' 1432 | 1433 | 1434 | ```php 1435 | class EstacaoDeRadio { \\classe que representa a estação de rádio 1436 | protected $frequencia; 1437 | 1438 | public function __construct(float $frequencia) { 1439 | $this->frequencia = $frequencia; 1440 | } 1441 | 1442 | public function getFrequencia() : float { 1443 | return $this->frequencia; 1444 | } 1445 | } 1446 | ``` 1447 | Aqui temos nosso iterador 1448 | 1449 | ```php 1450 | use Countable; 1451 | use Iterator; 1452 | 1453 | class EstacaoList implements Countable, Iterator { 1454 | /** @var EstacaoDeRadio[] $estacoes */ 1455 | protected $estacoes = []; 1456 | 1457 | /** @var int $contador */ 1458 | protected $contador; 1459 | 1460 | public function addEstacao(EstacaoDeRadio $estacao) { 1461 | $this->estacoes[] = $estacao; 1462 | } 1463 | 1464 | public function removeEstacao(EstacaoDeRadio $toRemove) { 1465 | $toRemoveFrequencia = $toRemove->getFrequencia(); 1466 | $this->estacoes = array_filter($this->estacoes, function (EstacaoDeRadio $estacao) use ($toRemoveFrequencia) { 1467 | return $estacao->getFrequencia() !== $toRemoveFrequencia; 1468 | }); 1469 | } 1470 | 1471 | public function count() : int { 1472 | return count($this->estacoes); 1473 | } 1474 | 1475 | public function current() : EstacaoDeRadio { 1476 | return $this->estacoes[$this->contador]; 1477 | } 1478 | 1479 | public function key() { 1480 | return $this->contador; 1481 | } 1482 | 1483 | public function next() { 1484 | $this->contador++; 1485 | } 1486 | 1487 | public function rewind() { 1488 | $this->contador = 0; 1489 | } 1490 | 1491 | public function valid(): bool 1492 | { 1493 | return isset($this->estacoes[$this->contador]); 1494 | } 1495 | } 1496 | ``` 1497 | E então ele pode ser usado como 1498 | ```php 1499 | $estacaoList = new EstacaoList(); 1500 | 1501 | $estacaoList->addEstacao(new Estacao(89)); 1502 | $estacaoList->addEstacao(new Estacao(101)); 1503 | $estacaoList->addEstacao(new Estacao(102)); 1504 | $estacaoList->addEstacao(new Estacao(103.2)); 1505 | 1506 | foreach($estacaoList as $estacao) { 1507 | echo $estacao->getFrequencia() . PHP_EOL; 1508 | } 1509 | 1510 | $estacaoList->removeEstacao(new Estacao(89)); // Iremos remover a estação 89 1511 | ``` 1512 | 1513 | 👽 Mediator 1514 | ======== 1515 | 1516 | 1517 | Exemplo do mundo real 1518 | > Um exemplo comum pode ser quando você fala com alguém em seu telefone celular, neste caso há um provedor de rede situado entre vocês e sua conversa passa através do provedor ao invés de ser enviada diretamente de um celular ao outro. Neste caso, o provedor de rede é mediador. 1519 | 1520 | Resumindo 1521 | > O pattern Mediator adiciona um objeto de terceiros (chamado mediador) para controlar a interação entre os dois objetos (chamados colegas). Isso ajuda a reduzir o acoplamento entre as classes que estão comunicando entre si. Pois agora elas não têm a necessidade de conhecer a implementação uma da outra. 1522 | 1523 | Wikipedia diz 1524 | > Na engenharia de software, o pattern mediator define um objeto que encapsula como conjunto de objetos interagem. Este pattern um pattern comportamental (behavioral pattern), pois ele pode alterar o comportamento do programa. 1525 | 1526 | **Exemplo Programático** 1527 | 1528 | Temos aqui um exemplo simples de uma sala de bate-papo (i.e. mediador) com usuários (i.e. colegas) enviando mensagens uns aos outros. 1529 | 1530 | Em primeiro lugar, temos o mediador, isto é, a sala de bate-papo 1531 | 1532 | 1533 | ```php 1534 | // Mediator 1535 | class ChatRoom implements ChatRoomMediator { 1536 | public function showMessage(User $user, string $message) { 1537 | $time = date('M d, y H:i'); 1538 | $sender = $user->getName(); 1539 | 1540 | echo $time . '[' . $sender . ']:' . $message; 1541 | } 1542 | } 1543 | ``` 1544 | 1545 | Então nós temos nossos usuários i.e. colegas 1546 | ```php 1547 | class User { 1548 | protected $name; 1549 | protected $chatMediator; 1550 | 1551 | public function __construct(string $name, ChatRoomMediator $chatMediator) { 1552 | $this->name = $name; 1553 | $this->chatMediator = $chatMediator; 1554 | } 1555 | 1556 | public function getName() { 1557 | return $this->name; 1558 | } 1559 | 1560 | public function send($message) { 1561 | $this->chatMediator->showMessage($this, $message); 1562 | } 1563 | } 1564 | ``` 1565 | E seu uso 1566 | ```php 1567 | $mediator = new ChatRoom(); 1568 | 1569 | $john = new User('John Doe', $mediator); 1570 | $jane = new User('Jane Doe', $mediator); 1571 | 1572 | $john->send('Olá!'); 1573 | $jane->send('Oi!'); 1574 | 1575 | // A saída será 1576 | // Feb 14, 10:58 [John]: Olá! 1577 | // Feb 14, 10:58 [Jane]: Hey! 1578 | ``` 1579 | 1580 | 💾 Memento 1581 | ------- 1582 | Exemplo do mundo real 1583 | > Veja o exemplo da calculadora (i.e. originador), onde sempre que você executa um cálculo, o último cálculo é salvo na memória (i.e. memento) assim você pode acessá-lo novamente e talvez retornar a ele pressionando alguns botões (i.e. armazenador). 1584 | 1585 | Resumindo 1586 | > O pattern Memento é sobre capturar e armazenar o estado atual de um objeto de uma forma que isso possa ser restaurado futuramente de forma tranquila. 1587 | 1588 | Wikipedia diz 1589 | > O pattern Memento é um design pattern que proporciona a habilidade de restaurar um objeto a seu estado anterior (desfazer por meio de reversão). 1590 | 1591 | 1592 | Normalmente útil quando você precisa fornecer uma funcionalidade como a de desfazer. 1593 | 1594 | **Exemplo Programático** 1595 | 1596 | Vamos utilizar o exemplo do editor de texto que continua guardando o estado de tempo em tempo e que você pode restaurar se quiser. 1597 | 1598 | Em primeiro lugar, temos o nosso objeto memento que poderá guardar o estado do editor 1599 | 1600 | 1601 | ```php 1602 | class EditorMemento { 1603 | protected $content; 1604 | 1605 | public function __construct(string $content) { 1606 | $this->content = $content; 1607 | } 1608 | 1609 | public function getContent() { 1610 | return $this->content; 1611 | } 1612 | } 1613 | ``` 1614 | 1615 | Então nós temos nosso editor i.e. originador que irá utilizar nosso objeto memento 1616 | 1617 | ```php 1618 | class Editor { 1619 | protected $content = ''; 1620 | 1621 | public function type(string $words) { 1622 | $this->content = $this->content . ' ' . $words; 1623 | } 1624 | 1625 | public function getContent() { 1626 | return $this->content; 1627 | } 1628 | 1629 | public function save() { 1630 | return new EditorMemento($this->content); 1631 | } 1632 | 1633 | public function restore(EditorMemento $memento) { 1634 | $this->content = $memento->getContent(); 1635 | } 1636 | } 1637 | ``` 1638 | 1639 | Em seguida o Editor pode ser usado da seguinte forma 1640 | 1641 | ```php 1642 | $editor = new Editor(); 1643 | 1644 | // Escreva alguma coisa 1645 | $editor->type('Esta é a primeira sentença.'); 1646 | $editor->type('Esta é a segunda.'); 1647 | 1648 | // Salva o estado, para restaurar para : Esta é a primeira sentença. Esta é a segunda. 1649 | $saved = $editor->save(); 1650 | 1651 | // Escreva mais alguma coisa 1652 | $editor->type('E esta é a terceira.'); 1653 | 1654 | // Saída: Conteúdo salvo anteriormente 1655 | echo $editor->getContent(); // Esta é a primeira sentença. Esta é a segunda. E esta é a terceira. 1656 | 1657 | // Restaura para o último estado salvo 1658 | $editor->restore($saved); 1659 | 1660 | $editor->getContent(); // Esta é a primeira sentença. Esta é a segunda. 1661 | ``` 1662 | 1663 | 😎 Observer 1664 | -------- 1665 | Exemplo do mundo real 1666 | > Um bom exemplo seriam pessoas que estão buscando emprego e que se inscrevem em algum site de divulgação de vagas e são notificados quando é anunciada uma oferta de emprego correspondente. 1667 | 1668 | Resumindo 1669 | > Define uma dependência entre objetos de maneira que quando um objeto altera seu estado, todos seus dependentes são notificados. 1670 | 1671 | Wikipedia diz 1672 | > O padrão Observer é um padrão de design de software no qual um objeto, chamado de objeto de interesse, mantêm uma lista de seus dependentes, chamados observadores, e os notifica automaticamente de qualquer alteração no estado, geralmente através de chamadas a um dos seus métodos. 1673 | 1674 | **Exemplo Programático** 1675 | 1676 | Traduzindo nosso exemplo acima. Primeiro, nós temos buscadores de emprego que precisam ser notificados de anúncios de vagas 1677 | ```php 1678 | class JobPost { 1679 | protected $title; 1680 | 1681 | public function __construct(string $title) { 1682 | $this->title = $title; 1683 | } 1684 | 1685 | public function getTitle() { 1686 | return $this->title; 1687 | } 1688 | } 1689 | 1690 | class JobSeeker implements Observer { 1691 | protected $name; 1692 | 1693 | public function __construct(string $name) { 1694 | $this->name = $name; 1695 | } 1696 | 1697 | public function onJobPosted(JobPost $job) { 1698 | // Do something with the job posting 1699 | echo 'Hi ' . $this->name . '! New job posted: '. $job->getTitle(); 1700 | } 1701 | } 1702 | ``` 1703 | Então nós temos nossa publicação de vagas na qual os que estão buscando emprego vão se inscrever 1704 | ```php 1705 | class JobPostings implements Observable { 1706 | protected $observers = []; 1707 | 1708 | protected function notify(JobPost $jobPosting) { 1709 | foreach ($this->observers as $observer) { 1710 | $observer->onJobPosted($jobPosting); 1711 | } 1712 | } 1713 | 1714 | public function attach(Observer $observer) { 1715 | $this->observers[] = $observer; 1716 | } 1717 | 1718 | public function addJob(JobPost $jobPosting) { 1719 | $this->notify($jobPosting); 1720 | } 1721 | } 1722 | ``` 1723 | Então pode ser usado como 1724 | ```php 1725 | // Cria buscadores de emprego 1726 | $johnDoe = new JobSeeker('John Doe'); 1727 | $janeDoe = new JobSeeker('Jane Doe'); 1728 | $kaneDoe = new JobSeeker('Kane Doe'); 1729 | 1730 | // Cria publicação de vagas e atribui buscadores 1731 | $jobPostings = new JobPostings(); 1732 | $jobPostings->attach($johnDoe); 1733 | $jobPostings->attach($janeDoe); 1734 | 1735 | // Adiciona uma nova vaga e verifica se os buscadores são notificados 1736 | $jobPostings->addJob(new JobPost('Software Engineer')); 1737 | 1738 | // Output 1739 | // Hi John Doe! New job posted: Software Engineer 1740 | // Hi Jane Doe! New job posted: Software Engineer 1741 | ``` 1742 | 1743 | 🏃 Visitor 1744 | ------- 1745 | Exemplo do mundo real 1746 | > Considere alguém visitando Dubai. Eles só precisam de uma maneira (i.e. visto) para entrar em Dubai. Após a chegada, eles podem visitar qualquer lugar de Dubai por conta própria sem ter que pedir permissão ou para caminhar a fim de visitar qualquer lugar aqui; basta saber a respeito do lugar e eles podem visitá-lo. O padrão Visitor deixa você fazer justamente isso, ele ajuda você a adicionar lugares a serem visitados de maneira que eles possam visitar o máximo de locais possíveis sem a necessidade de caminhar para encontrá-los. 1747 | 1748 | Resumindo 1749 | > O padrão Visitor permite que você adicione operações adicionais a objetos sem ter que modificá-los. 1750 | 1751 | Wikipedia diz 1752 | > Na programação orientada a objetos e engenharia de software, o padrão de design visitor é uma maneira de separar um algoritmo da estrutura de um objeto no qual ele opera. Um resultado prático dessa separação é a habilidade de adicionar novas operações a objetos existentes sem ter que modificar suas estruturas. É uma maneira de seguir o princípio de aberto/fechado. 1753 | 1754 | **Exemplo Programático** 1755 | 1756 | Vamos tomar como exemplo uma simulação de zoológico onde nós temos vários tipos diferentes de animais e temos que fazer eles emitirem Sons. Vamos traduzir isso utilizando o padrão visitor 1757 | 1758 | ```php 1759 | // Visitado 1760 | interface Animal { 1761 | public function accept(AnimalOperation $operation); 1762 | } 1763 | 1764 | // Visitor 1765 | interface AnimalOperation { 1766 | public function visitMonkey(Monkey $monkey); 1767 | public function visitLion(Lion $lion); 1768 | public function visitDolphin(Dolphin $dolphin); 1769 | } 1770 | ``` 1771 | Então nós temos nossas implementações para os animais 1772 | ```php 1773 | class Monkey implements Animal { 1774 | 1775 | public function shout() { 1776 | echo 'Ooh oo aa aa!'; 1777 | } 1778 | 1779 | public function accept(AnimalOperation $operation) { 1780 | $operation->visitMonkey($this); 1781 | } 1782 | } 1783 | 1784 | class Lion implements Animal { 1785 | 1786 | public function roar() { 1787 | echo 'Roaaar!'; 1788 | } 1789 | 1790 | public function accept(AnimalOperation $operation) { 1791 | $operation->visitLion($this); 1792 | } 1793 | } 1794 | 1795 | class Dolphin implements Animal { 1796 | 1797 | public function speak() { 1798 | echo 'Tuut tuttu tuutt!'; 1799 | } 1800 | 1801 | public function accept(AnimalOperation $operation) { 1802 | $operation->visitDolphin($this); 1803 | } 1804 | } 1805 | ``` 1806 | Vamos implementar nosso visitor 1807 | ```php 1808 | class Speak implements AnimalOperation { 1809 | public function visitMonkey(Monkey $monkey) { 1810 | $monkey->shout(); 1811 | } 1812 | 1813 | public function visitLion(Lion $lion) { 1814 | $lion->roar(); 1815 | } 1816 | 1817 | public function visitDolphin(Dolphin $dolphin) { 1818 | $dolphin->speak(); 1819 | } 1820 | } 1821 | ``` 1822 | 1823 | E pode ser usado como 1824 | ```php 1825 | $monkey = new Monkey(); 1826 | $lion = new Lion(); 1827 | $dolphin = new Dolphin(); 1828 | 1829 | $speak = new Speak(); 1830 | 1831 | $monkey->accept($speak); // Ooh oo aa aa! 1832 | $lion->accept($speak); // Roaaar! 1833 | $dolphin->accept($speak); // Tuut tutt tuutt! 1834 | ``` 1835 | Nós poderíamos ter feito isso simplesmente tendo uma hierarquia de herança para os animais, mas aí teríamos que modificar os animais sempre que precisássemos adicionar novas ações a eles. Mas agora não precisaremos alterá-los. Por exemplo, vamos supor que nos pediram para adicionar o comportamento de pulo aos animais, nós podíamos adicionar isso criando um novo visitor i.e. 1836 | 1837 | ```php 1838 | class Jump implements AnimalOperation { 1839 | public function visitMonkey(Monkey $monkey) { 1840 | echo 'Jumped 20 feet high! on to the tree!'; 1841 | } 1842 | 1843 | public function visitLion(Lion $lion) { 1844 | echo 'Jumped 7 feet! Back on the ground!'; 1845 | } 1846 | 1847 | public function visitDolphin(Dolphin $dolphin) { 1848 | echo 'Walked on water a little and disappeared'; 1849 | } 1850 | } 1851 | ``` 1852 | E para utilização 1853 | ```php 1854 | $jump = new Jump(); 1855 | 1856 | $monkey->accept($speak); // Ooh oo aa aa! 1857 | $monkey->accept($jump); // Jumped 20 feet high! on to the tree! 1858 | 1859 | $lion->accept($speak); // Roaaar! 1860 | $lion->accept($jump); // Jumped 7 feet! Back on the ground! 1861 | 1862 | $dolphin->accept($speak); // Tuut tutt tuutt! 1863 | $dolphin->accept($jump); // Walked on water a little and disappeared 1864 | ``` 1865 | 1866 | 💡 Strategy 1867 | -------- 1868 | 1869 | Exemplo do mundo real 1870 | > Considere o exemplo de ordenação, nós implementamos o algoritmo de Bubble Sort mas a quantidade de dados começou a crescer e o algoritmo começou a ficar muito lento. Para contornar o problema nós implementamos o Quick Sort. Embora o algoritmo Quick Sort performe melhor para conjuntos de dados muito grandes, era muito lento para conjuntos menores. Para resolver a situação implementamos uma estratégia na qual para conjuntos de dados pequenos, seja utilizado o Bubble Sort e para conjuntos de dados maiores, utilizado o Quick Sort. 1871 | 1872 | Resumindo 1873 | > O padrão de Strategy permite a troca de algoritmo ou estratégia baseado na situação. 1874 | 1875 | Wikipedia diz 1876 | > Na programação de computadoes, o padrão Strategy (também conhecido como padrão Policy) é um padrão comportamental de design de software que permite que o comportamento de um algoritmo seja selecionado em tempo de execução. 1877 | 1878 | **Exemplo Programático** 1879 | 1880 | Traduzindo nosso exemplo acima. Primeiramente devemos ter nossa interface de Strategy e diferentes implementações de estratégia. 1881 | 1882 | ```php 1883 | interface SortStrategy { 1884 | public function sort(array $dataset) : array; 1885 | } 1886 | 1887 | class BubbleSortStrategy implements SortStrategy { 1888 | public function sort(array $dataset) : array { 1889 | echo "Sorting using bubble sort"; 1890 | 1891 | // Do sorting 1892 | return $dataset; 1893 | } 1894 | } 1895 | 1896 | class QuickSortStrategy implements SortStrategy { 1897 | public function sort(array $dataset) : array { 1898 | echo "Sorting using quick sort"; 1899 | 1900 | // Do sorting 1901 | return $dataset; 1902 | } 1903 | } 1904 | ``` 1905 | 1906 | E temos nosso client, que vai utilizar qualquer uma das estratégias 1907 | 1908 | ```php 1909 | class Sorter { 1910 | protected $sorter; 1911 | 1912 | public function __construct(SortStrategy $sorter) { 1913 | $this->sorter = $sorter; 1914 | } 1915 | 1916 | public function sort(array $dataset) : array { 1917 | return $this->sorter->sort($dataset); 1918 | } 1919 | } 1920 | ``` 1921 | 1922 | E pode ser usado como 1923 | ```php 1924 | $dataset = [1, 5, 4, 3, 2, 8]; 1925 | 1926 | $sorter = new Sorter(new BubbleSortStrategy()); 1927 | $sorter->sort($dataset); // Output : Sorting using bubble sort 1928 | 1929 | $sorter = new Sorter(new QuickSortStrategy()); 1930 | $sorter->sort($dataset); // Output : Sorting using quick sort 1931 | ``` 1932 | 1933 | 💢 State 1934 | ----- 1935 | Exemplo do mundo real 1936 | > Imagine que você está utilizando alguma aplicação gráfica e escolhe um pincel para desenhar. O pincel muda seu comportamento baseado na cor selecionada i.e. se você seleciona a cor vermelha, ele irá desenhar em vermelho, se selecionar azul então será em azul etc. 1937 | 1938 | Resumindo 1939 | > Permite que você mude o comportamento de uma classe quando o estado muda. 1940 | 1941 | Wikipedia diz 1942 | > O padrão State é um padrão comportamental de design de software que implementa uma máquina de estados de maneira orientada à objetos. Com o padrão State, uma máquina de estados é implementada através da implementação de cada um dos estados individuais como uma classe derivada da interface do padrão State, e implementando transições de estado através de chamadas de métodos definidos na superclasse do padrão. 1943 | > O padrão State pode ser interpretado como um padrão de estratégia que é capaz de alterar a estratégia corrente através de invocações de métodos definidos na interface do padrão. 1944 | 1945 | **Exemplo Programático** 1946 | 1947 | Vamos tomar como exemplo um editor de texto, ele permite que você altere o estado do texto que é digitado i.e. se você selecionou negrito, irá começar a escrever em negrito, se selecionou itálico então em itálico etc. 1948 | 1949 | Primeiramente temos nossa interface de estado e algumas implementações de estado. 1950 | 1951 | ```php 1952 | interface WritingState { 1953 | public function write(string $words); 1954 | } 1955 | 1956 | class UpperCase implements WritingState { 1957 | public function write(string $words) { 1958 | echo strtoupper($words); 1959 | } 1960 | } 1961 | 1962 | class LowerCase implements WritingState { 1963 | public function write(string $words) { 1964 | echo strtolower($words); 1965 | } 1966 | } 1967 | 1968 | class Default implements WritingState { 1969 | public function write(string $words) { 1970 | echo $words; 1971 | } 1972 | } 1973 | ``` 1974 | Então nós temos nosso editor 1975 | ```php 1976 | class TextEditor { 1977 | protected $state; 1978 | 1979 | public function __construct(WritingState $state) { 1980 | $this->state = $state; 1981 | } 1982 | 1983 | public function setState(WritingState $state) { 1984 | $this->state = $state; 1985 | } 1986 | 1987 | public function type(string $words) { 1988 | $this->state->write($words); 1989 | } 1990 | } 1991 | ``` 1992 | Então pode ser usado como 1993 | ```php 1994 | $editor = new TextEditor(new Default()); 1995 | 1996 | $editor->type('First line'); 1997 | 1998 | $editor->setState(new UpperCaseState()); 1999 | 2000 | $editor->type('Second line'); 2001 | $editor->type('Third line'); 2002 | 2003 | $editor->setState(new LowerCaseState()); 2004 | 2005 | $editor->type('Fourth line'); 2006 | $editor->type('Fifth line'); 2007 | 2008 | // Output: 2009 | // First line 2010 | // SECOND LINE 2011 | // THIRD LINE 2012 | // fourth line 2013 | // fifth line 2014 | ``` 2015 | 2016 | 📒 Template Method 2017 | --------------- 2018 | 2019 | Exemplo do mundo real 2020 | > Suponha que estejamos construindo uma casa. Os passos para sua construção podem se parecer com 2021 | > - Preparar o alicerce da casa 2022 | > - Construir os muros 2023 | > - Construir um teto 2024 | > - Construir outros andares 2025 | 2026 | > A ordem destes passos não pode ser mudada i.e. Você não pode construir um teto antes de construir as paredes e etc mas cada um dos passos pode ser modificado, por exemplo, muros podem ser construídos de madeira, poliéster ou pedra. 2027 | 2028 | Resumindo 2029 | > O Template method define o esqueleto de como um algoritmo pode ser executado, mas delega a implementação destes passos para a classes filhas. 2030 | 2031 | A Wikipedia diz 2032 | > Na engenharia de software, o padrão template method é um padrão de projeto comportamental que define o esqueleto de programa de um algoritmo em operação, delegando alguns passos para as subclasses. Ele permite que seja possível redefinir alguns passos do algoritmo sem mudar a estrutura do mesmo. 2033 | 2034 | **Exemplo Programático** 2035 | 2036 | Imagine que tenhamos uma build tool que nos auxilia a testar, fazer análise de código, criar a build, gerar relatórios da build (i.e. relatórios de cobertura, relatórios de análise de código etc) e dar deploy do nosso app no servidor de testes. 2037 | 2038 | Primeiramente, temos nossa classe base que especifica o esqueleto para o algoritmo de build 2039 | ```php 2040 | abstract class Builder { 2041 | 2042 | // Template method 2043 | public final function build() { 2044 | $this->test(); 2045 | $this->lint(); 2046 | $this->assemble(); 2047 | $this->deploy(); 2048 | } 2049 | 2050 | public abstract function test(); 2051 | public abstract function lint(); 2052 | public abstract function build(); 2053 | public abstract function deploy(); 2054 | } 2055 | ``` 2056 | 2057 | Então, podemos ter nossa implementação 2058 | 2059 | ```php 2060 | class AndroidBuilder extends Builder { 2061 | public function test() { 2062 | echo 'Rodando testes do android'; 2063 | } 2064 | 2065 | public function lint() { 2066 | echo 'Análisando o código do android'; 2067 | } 2068 | 2069 | public function assemble() { 2070 | echo 'Montando a build do android'; 2071 | } 2072 | 2073 | public function deploy() { 2074 | echo 'Fazendo o deploy da build do android para o servidor'; 2075 | } 2076 | } 2077 | 2078 | class IosBuilder extends Builder { 2079 | public function test() { 2080 | echo 'Rodando testes do ios'; 2081 | } 2082 | 2083 | public function lint() { 2084 | echo 'Análisando o código do ios'; 2085 | } 2086 | 2087 | public function assemble() { 2088 | echo 'Montando a build do ios'; 2089 | } 2090 | 2091 | public function deploy() { 2092 | echo 'Fazendo o deploy da build do ios para o servidor'; 2093 | } 2094 | } 2095 | ``` 2096 | Que então, podem ser usadas como 2097 | 2098 | ```php 2099 | $androidBuilder = new AndroidBuilder(); 2100 | $androidBuilder->build(); 2101 | 2102 | // Output: 2103 | // Rodando testes do android 2104 | // Análisando o código do android 2105 | // Montando a build do android 2106 | // Fazendo o deploy da build do android para o servidor 2107 | 2108 | $iosBuilder = new IosBuilder(); 2109 | $iosBuilder->build(); 2110 | 2111 | // Output: 2112 | // Rodando testes do ios 2113 | // Análisando o código do ios 2114 | // Montando a build do ios 2115 | // Fazendo o deploy da build do ios para o servidor 2116 | ``` 2117 | 2118 | ## 🚦 Envolva-se 2119 | 2120 | E isto é sobre envolver-se. Irei continuar a melhorar este arquivo, então é possível que você queira clicar em watch/star deste repositório para reve-lo no futuro. A, também tenho planos para escrever um repositório semelhante sobre Padrões de Arquitetura (archtectural patterns), fique ligado! 2121 | 2122 | ## 👬 Contribuição 2123 | - Reporte issues 2124 | - Abra um pull request com melhorias 2125 | - Espelhe aos amigos 2126 | 2127 | Este repositório foi do inglês traduzido [daqui](https://github.com/kamranahmedse/design-patterns-for-humans) 2128 | e você pode encontrar o autor original em kamranahmed.se@gmail.com ou [@kamranahmedse](http://twitter.com/kamranahmedse) 2129 | 2130 | ## Licensa 2131 | MIT © [Kamran Ahmed](http://kamranahmed.info) 2132 | --------------------------------------------------------------------------------