├── 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 | 
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 | 
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 |
--------------------------------------------------------------------------------