## Design Patterns <br /> <br /> ###### Eduardo Lopes Ferreira <br /><i class="fa fa-github"></i>[@eduardo1306](https://www.github.com/eduardo1306) <br /> --- ## Sumário <br /> ###### <span>1. <!-- .element: class="fragment" data-fragment-index="1" -->**S.O.L.I.D**<!-- .element: class="fragment" data-fragment-index="1" --></span><br /> <span>2.<!-- .element: class="fragment" data-fragment-index="2" --> **Creational Design Patterns**<!-- .element: class="fragment" data-fragment-index="2" --></span><br /> <span>3.<!-- .element: class="fragment" data-fragment-index="3" --> **Dependency Injection**<!-- .element: class="fragment" data-fragment-index="3" --></span><br /> <span>4.<!-- .element: class="fragment" data-fragment-index="4" --> **Structural Design Patterns**<!-- .element: class="fragment" data-fragment-index="4" --></span><br /> --- ## S.O.L.I.D ###### São príncipios da programação para boas práticas na hora de desenvolver o código e resolver problemas curriqueiros <br /> <span>- **S**ingle Responsability<!-- .element: class="fragment" data-fragment-index="1" --></span><br /> <span>- **O**pen/Closed<!-- .element: class="fragment" data-fragment-index="2" --></span><br /> <span>- **L**iskov Substitution<!-- .element: class="fragment" data-fragment-index="3" --></span><br /> <span>- **I**nterface Segregation<!-- .element: class="fragment" data-fragment-index="4" --></span><br /> <span>- **D**ependency Inversion<!-- .element: class="fragment" data-fragment-index="5" --></span><br /> --- ## Single Responsability Principle ###### Cada classe deve ter apenas uma responsabilidade. ![](https://miro.medium.com/max/1000/1*P3oONz9Da3Tc1w97fMV73Q.png =750x450) --- ## Open/Closed Principle ###### Uma classe deve ser aberta a extensões e fechada para modificações. ![](https://miro.medium.com/max/1000/1*0MtFBmm6L2WVM04qCJOZPQ.png =750x450)<br /> --- ## Liskov Substitution Principle ###### Uma subclasse deve performar as mesmas ações de uma classe. ![](https://miro.medium.com/max/1000/1*yKk2XKJaCLNlDxQMx1r55Q.png =750x450)<br /> --- ## Interface Segregation Principle ###### As classes devem depender de implementações de interfaces, de forma que não seja generalizada. ![](https://miro.medium.com/max/1350/1*2hmyR9L43Vm64MYxj4Y89w.png =750x450) --- ## Dependency Inversion Principle ###### Uma classe não deve ser conectada diretamente a uma ferramenta e sim a uma interface. ![](https://miro.medium.com/max/1000/1*Qk8tDmjQlyvwKxNTfXIo0Q.png =750x450)<br /> --- ## Creational Design Patterns ###### São Design Patterns que permitem criação de objetos da melhor maneira possível. São eles: <br /> <span>-<!-- .element: class="fragment" data-fragment-index="1" --> **Singleton**<!-- .element: class="fragment" data-fragment-index="1" --></span><br /> <span>-<!-- .element: class="fragment" data-fragment-index="2" --> **Factory**<!-- .element: class="fragment" data-fragment-index="2" --></span><br /> <span>-<!-- .element: class="fragment" data-fragment-index="3" --> **Loose Coupling**<!-- .element: class="fragment" data-fragment-index="3" --></span><br /> <br /> --- ## Singleton ###### Tem como característica uma única instância em toda a aplicação. ```typescript export class Human { height: number = 0; weight: number = 0; age: number = 0; constructor() { if(Human._instance) { throw new Error ('Cannot initialize singleton class using new!'); } Human._instance = this; } private static _instance: Human = new Human(); public static get instance(): Human { return Human._instance; } } let eduardo = Human._instance; ``` --- ## Factory ###### Permite possibilidades de criar objetos em tempo de execução, isentando de instanciar cada classe. ```typescript export interface ITransport { deliver(): void; } class Truck implements ITransport { public deliver(): void { console.log("Shipping by the road!"); } } class Boat implements ITransport { public deliver(): void { console.log("Shipping by the sea!"); } } export class ShippingCompany { static getTruck(): Truck { return new Truck(); } static getBoat(): Boat { return new Boat(); } } ShippingCompany.getTruck().deliver(); // Shipping by the road; ShippingCompany.getBoat().deliver(); // Shipping by the sea; ``` --- ## Loose Coupling ###### Permite que vários componentes interligados em uma aplicação possam compartilhar/conversar de forma que as classes não se dependam entre elas, apenas usando a implementação da interface. ```typescript= export interface IPost { id: number; title: string; body: string; author: string; } export interface IPostsServices { getAll(): Promise<IPost[]>; save(post: IPost): Promise<void>; } export interface IExportPostsServices { export(post: IPost[]): string; } export default class PostsServices implements IPostsServices { private _posts: IPost[] = []; constructor() { this._posts = [ { id: 4, title: 'Instagram is awesome', body: 'Something important', author: 'Mark Zuckerberg', }, { id: 5, title: 'Netflix is awesome', body: 'Something important', author: 'Reed Hastings', }, ] } getAll(): Promise<IPost[]> { return Promise.resolve(this._posts); } save(post: IPost): Promise<void> { this._posts.push(post); return Promise.resolve(); } export(service: IExportPostsServices): Promise<string> { return this.getAll().then(posts => service.export(posts)); } } export class MockPostServices implements IPostsServices { posts: IPost[] = []; constructor() { this.posts = [ { id: 1, title: 'Facebook is awesome!' , body: 'Something important', author: 'Mark Zuckerberg', }, { id: 2, title: 'Microsoft is awesome!' , body: 'Something important', author: 'Bill Gates', }, ] } getAll(): Promise<IPost[]> { return Promise.resolve(this.posts); } save(post: IPost): Promise<void> { this.posts.push(post); return Promise.resolve(); } export(service: IExportPostsServices): Promise<string> { return this.getAll().then(posts => service.export(posts)); } } export class JSONExportServices implements IExportPostsServices { export(posts: IPost[]): string { return JSON.stringify(posts); } } let mockService = new MockPostServices() mockService.export(new JSONExportServices).then(posts => console.log(posts)); ``` --- ## Dependency Injection <br /><span>-<!-- .element: class="fragment" data-fragment-index="1" --> **Como/Por que utilizar** <!-- .element: class="fragment" data-fragment-index="1" --></span><br /> <span>-<!-- .element: class="fragment" data-fragment-index="2" --> **Injeção de Dependência e Inversão de Dependência**<!-- .element: class="fragment" data-fragment-index="2" --></span><br /> <span>-<!-- .element: class="fragment" data-fragment-index="3" --> **Containers (Tsyringe)**<!-- .element: class="fragment" data-fragment-index="3" --></span><br /> --- ## Como/Por que utilizar ###### Ajuda a evitar o alto nível de acoplamento do código. Facilitando a manutenção/implementação de novas funcionalidades. <br /> ```typescript export default class Notification { public notify(): void { console.log('Notify my friends'); } } export default class Post { constructor(private notification: Notification) { } public publish(text: string): void { console.log(text); this.notification.notify(); } } const post = new Post(new Notification); post.publish('Design Patterns are Awesome!!'); // Notify my friends ``` --- ## Injeção de Dependência e Inversão de Dependência ###### A combinação dos dois é bastante utilizado para abstrairmos o máximo da depêndencia direta. ```typescript import ICreateAppointmentsDTO from '@modules/appointments/dtos/ICreateAppointmentsDTO'; import Appointment from '../typeorm/entities/Appointments'; export default interface IAppointmentsRepository { create(data: ICreateAppointmentsDTO): Promise<Appointment>; findByDate(date: Date): Promise<Appointment | undefined>; } @injectable() class CreateAppointmentService { constructor( @inject('AppointmentsRepository') private appointmentsRepository: IAppointmentsRepository, ) {} ``` --- ## Containers (Tsyringe) ###### São gerenciadores e automatizadores de instânciação e injeção de dependência.<br /> O Tsyringe é uma lib desenvolvida pela Microsoft com o intuito de criar containers para utilizarmos a injeção de dependência. ```typescript import { container } from 'tsyringe'; import '@modules/users/providers'; import './providers'; import IAppointmentsRepository from '@modules/appointments/repositories/IAppointmensRepository'; import AppointmentsRepository from '@modules/appointments/infra/typeorm/repository/AppointmentsRepository'; import IUsersRepository from '@modules/users/repositories/IUserRepository'; import UsersRepository from '@modules/users/infra/typeorm/repositories/UserRepository'; container.registerSingleton<IAppointmentsRepository>( 'AppointmentsRepository', AppointmentsRepository, ); container.registerSingleton<IUsersRepository>( 'UsersRepository', UsersRepository, ); ``` --- ## Structural Design Patterns <br /><span>-<!-- .element: class="fragment" data-fragment-index="1" --> **Decorators** <!-- .element: class="fragment" data-fragment-index="1" --></span><br /> <span>-<!-- .element: class="fragment" data-fragment-index="2" --> **Adapter**<!-- .element: class="fragment" data-fragment-index="2" --></span><br /> <span>-<!-- .element: class="fragment" data-fragment-index="3" --> **Facade**<!-- .element: class="fragment" data-fragment-index="3" --></span><br /> --- ## Decorators ###### Permitem adicionar novos comportamentos aos objetos. ```typescript abstract class Car { public description: string; public getDescription(): string { return this.description; }; public abstract cost(): number; } class Renegade extends Car { public description = 'Reneage'; public cost(): number { return 8800; } } class Troller extends Car { public description = 'Troller 4x4' public cost(): number { return 14000; } } abstract class CarOptions extends Car { decoratedCar: Car; public abstract getDescription(): string; public abstract cost(): number; } class LeatherSeat extends CarOptions { constructor(public car: Car){ super(); this.decoratedCar = car; } public getDescription(): string { return this.decoratedCar.getDescription() + ' with leather seat!'; } public cost(): number { return this.decoratedCar.cost() + 100; } } let renegade = new Renegade(); let troller = new Troller(); renegade = new LeatherSeat(renegade); troller = new LeatherSeat(troller); ``` --- ## Adapter ###### Permite adaptar objetos com interfaces incompatíveis. ```typescript interface IPhone { useLightning(): void; } interface Android { useMicroUSB(): void; } class iPhone11 implements IPhone { useLightning(): void { console.log('using lightning port...'); } } class Samsung implements Android { useMicroUSB(): void { console.log('using micro USB...') } } class LightningToMicroUSBAdapter implements Android { constructor(private iphone: IPhone){} useMicroUSB(): void { console.log('Want to use micro USB, converting to lightning...'); this.iphone.useLightning(); } } ``` --- ## Facade ###### Sintetiza o encapsulamento com interface simples estruturando um módulo por completo. ![](https://i.imgur.com/EbaGzGF.png =750x450) --- ## Bibliografias - https://www.udemy.com/course/design-patterns-in-typescript/learn/lecture/11677766#overview - https://www.youtube.com/watch?v=WPOLDEk1LF0 - https://medium.com/backticks-tildes/the-s-o-l-i-d-principles-in-pictures-b34ce2f1e898 - https://refactoring.guru/pt-br/design-patterns/catalog - https://github.com/microsoft/tsyringe ---
{"metaMigratedAt":"2023-06-15T11:07:57.906Z","metaMigratedFrom":"YAML","title":"Design Patterns","breaks":true,"slideOptions":"{\"transition\":\"slide\"}","contributors":"[{\"id\":\"a20e5c4b-eacd-4a91-873f-bbc6816f7cf6\",\"add\":18377,\"del\":6248}]"}
    187 views