SOLID 소개 - Princípios L e I

타벨라 데 콘테우도스


  • Liskov Substitution Principle
  • Interface Segregation Principle
  • Links Úteis



  • Liskov 대체 원리



    추천



    O Princípio de Substituição de Liskov diz que devemos poder utilizar uma sub-classe, no lugar de uma super-classe. Na prática isso ocorre da implementação de Interfaces, ou através da herança de class, dessa forma toda a sub-classe que implementa determinada interface, ou herda de determinada super-classe, deve poder ser usada como substituto.

    예시



    A forma mais fácil de se entender o Princípio de Substituição de Liskov é através de classes que fazem a conexão com o banco de dados, dessa forma podemos ter diversas classes, responsáveis ​​por diversos bancos, podendo se substituírem sem a geração de efeitos colaterais (버그 ).

    MySQL과 MongoDB가 다른 DB와는 다른 상황에서 일반적으로 사용되는 주요 문제의 예가 아닙니다. Para isso iremos criar duas classes que implementam uma mesma Interface e utilizá-las da mesma forma.

    interface IUserRepository {
      create(name: string, age: number): Promise<void>;
    }
    



    import mysql from 'mysql2/promise';  // Esse pacote foi utilizado apenas como exemplo
    
    class UserRepositoryMySQL implements IUserRepository {
      constructor() {
        this.mysql = mysql.createPool({
          /* configuração da conexão */
        });
      }
    
        async create(name: string, age: number): Promise<void> {
          await this.mysql.execute(
            'INSERT INTO users (name, age) VALUES (?, ?);',
            [name, age]
          )
        }
      }
    



    import { User } from 'mongooseModels';  // pasta "fictícia"que armazena as Models do Mongoose
    
    class UserRepositoryMongo implements IUserRepository {
      constructor() {
        this.userModel = new User();
      }
    
      async create(name: string, age: number): Promise<void> {
        await this.userMode.create({ name, age });
      }
    }
    



    import { IUserRepository } from 'IUserRepository';
    
    class CreateUSerService {
      constructor(private userRepository: IUserRepository) {}
    
      async execute(name: string, age: number) {
        this.userRepository.create(name, age);
      }
    }
    



    import { Request, Response, NextFunction } from 'express';
    
    import { UserRepositoryMySQL } from 'UserRepositoryMySQL';
    import { UserRepositoryMongo } from 'UserRepositoryMongo';
    
    import { CreateUserService } from 'CreateUserService';
    
    const userRepositoryMySQL = new UserRepositoryMySQL();
    const userRepositoryMongo = new UserRepositoryMongo();
    
    /* ---------- Criando usuário no MySQL ---------- */
    const createUserService = new CreateUserService(userRepositoryMySQL);
    /* ---------- ----------------------- ---------- */
    
    /* ---------- Criando usuário no MongoDB ---------- */
    const createUserService = new CreateUserService(userRepositoryMongo);
    /* ---------- ------------------------- ---------- */
    
    const createUserRoute = async (req: Request, res: Response, next: NextFunction) => {
      const { name, age } = req.body;
    
      try {
        await createUserService.execute(name, age);
        res.status(200).end();
      } catch {
        res.status(500).json({ message: 'Internal server error' });
      }
    }
    


    No example acima criamos duas classes que lidam com DB diferentes, porém podemos utilizar qualquer uma das duas em nosso serviço de criação de usuário CreateUSerService , isso porque o serviço espera a Interface IUserRepository e como nossas classes implementam essa Interface podem ser usadas 코모 대체.

    Voltar ao top


    인터페이스 분리 원리



    추천



    O Princípio de Segregação de Interfaces recomenda que separemos nossas interface em "blocos mínimos", em outras palavras, as criemos altamente especializadas e caso surja a necessidade, podemos criar uma Interface mais completa estendendo as mais específicas.

    예시



    O Princípio de Segregação de Interfaces é, na minha opinião, o mais simples de se entender o conceito teórico, porém o mais difícil de se aplicar em um caso real.

    Nosso example será uma classe de serviço de uma API, ele deverá obrigatoriamente possuir o método execute para executar sua tarefa e opcionalmente poderá possuir métodos de validação, como por example: validar se um email já está em uso.

    // Iremos utilizar generics para "tipar" o input <T> e o output <O> posteriormente
    
    interface IServiceExecute<T, O> {
      execute(T): Promise<O>;
    }
    
    interface IServiceValidUnique<T> {
      isUnique(T): Promise<boolean>;
    }
    



    interface IRequest {
      username: string;
      email: string;
      password: string;
    }
    
    interface ICreatedUser extends IRequest {
      id: string;
    }
    
    type UniqueUser = Pick<IRequest, 'email'>
    
    class RegisterUserService implements IServiceExecute<IRequest | null, ICreateUser>, IServiceValidUnique<UniqueUser> {
      constructor(private repository: IRepository) {}
    
      async isUnique({ email }: UniqueUSer): Promise<boolean> {
        const emailAlreadyInUse = await this.repository.find(email);
    
        if (emailAlreadyInUse) {
          return false;
        }
    
        return true;
      }
    
      async execute({ username, email, password }: IRequest): Promise<ICreatedUser> {
        const isUnique = await this.isUnique({ email });
    
        if (!isUnique) {
          return null;
        }
    
        const newUSer = await this.repository.create({ username, email, password });
        return newUser;
      }
    }
    


    예를 들어 ACIMA ESTAMOS ALICANDO DUAS 인터페이스가 없습니다. 인터페이스는 UM UM úNICA CLASSE, ISSO PORQUE CADA 인터페이스 É RESPONSáVEL APENAS POR UM FUNCIONIDADE, DESA FORMA SE precisarmos construir UM serviço que não precision de validação, podemos apenas implementar aIServiceExecute .

    Obs: As Interfaces criadas junto da classe são um "complemento"as outras, isso porque optei por utilizar Generics na criação das Interfaces de serviço, logo é necessário inferir seu tipo posteriormente através de tipos primitivos, types ou interfaces .

    Voltar ao top


    링크 Úteis



  • Princípios SOLID com TypeScript 의해 Matheus Bessa

  • Os Princípios do SOLID — ISP Princípio de segregação da interface 의해 Jones Roberto

  • Os Princípios do SOLID — LSP -Princípio da substituição de Liskov 의해 Jones Roberto

  • Voltar ao top

    좋은 웹페이지 즐겨찾기