DEV Community

Cover image for (I): Aplicando o "Princípio da Segregação da Interface" com Typescript e Java
Victor Lima Reboredo
Victor Lima Reboredo

Posted on

(I): Aplicando o "Princípio da Segregação da Interface" com Typescript e Java

Conceitos

SOLID é um acrônimo que representa cinco princípios fundamentais da programação orientada a objetos, propostos por Robert C. Martin - o uncle Bob. Aqui você pode ler mais sobre o artigo dele.
Esses princípios têm como objetivo melhorar a estrutura e a manutenção do código, tornando-o mais flexível, escalável e fácil de entender. Tais princípios auxiliam o programador a criar códigos mais organizados, dividindo responsabilidades, reduzindo dependências, simplificando o processo de refatoração e promovendo a reutilização do código.

O "I" do acrônimo significa "Interface Segregation Principle". A frase que o uncle bob utilizou para definir esse princípio foi:

"Nenhum cliente deve ser forçado a depender de interfaces que não utiliza"

O Princípio da Segregação da Interface aborda um problema comum: interfaces excessivamente grandes que forçam implementações desnecessárias em classes que não precisam delas.

Aplicação prática

Imagine um sistema de autenticação em uma aplicação, onde diferentes métodos são usados para autenticar um usuário (e.g., por senha, por biometria, por QR Code).

Primeiro, vejamos a aplicação dessa classe sem utilizar o ISP em Java e Typescript:

Java

interface Authenticator {
    boolean authenticateWithPassword(String userId, String password);
    boolean authenticateWithBiometrics(String userId);
    boolean authenticateWithQRCode(String qrCode);
}

class PasswordAuthenticator implements Authenticator {
    @Override
    public boolean authenticateWithPassword(String userId, String password) {
        System.out.println("Authenticating with password...");
        return true;
    }

    @Override
    public boolean authenticateWithBiometrics(String userId) {
        throw new UnsupportedOperationException("Not implemented");
    }

    @Override
    public boolean authenticateWithQRCode(String qrCode) {
        throw new UnsupportedOperationException("Not implemented");
    }
}

Enter fullscreen mode Exit fullscreen mode

Typescript

interface Authenticator {
  authenticateWithPassword(userId: string, password: string): boolean;
  authenticateWithBiometrics(userId: string): boolean;
  authenticateWithQRCode(qrCode: string): boolean;
}

class PasswordAuthenticator implements Authenticator {
  authenticateWithPassword(userId: string, password: string): boolean {
    console.log("Authenticating with password...");
    return true;
  }

  authenticateWithBiometrics(userId: string): boolean {
    throw new Error("Not implemented");
  }

  authenticateWithQRCode(qrCode: string): boolean {
    throw new Error("Not implemented");
  }
}
Enter fullscreen mode Exit fullscreen mode

Problemas:

  1. Métodos não utilizados: A classe PasswordAuthenticator implementa métodos que não fazem sentido para sua função.
  2. Manutenção problemática: Se a interface mudar, todas as classes implementadoras precisam ser alteradas, mesmo que não utilizem os métodos novos.
  3. Violação de responsabilidade única: As classes começam a lidar com preocupações que não deveriam ser delas.

Para resolver o problema, podemos dividir a interface Authenticator em interfaces menores e mais específicas.

Java

interface PasswordAuth {
    boolean authenticateWithPassword(String userId, String password);
}

interface BiometricAuth {
    boolean authenticateWithBiometrics(String userId);
}

interface QRCodeAuth {
    boolean authenticateWithQRCode(String qrCode);
}

class PasswordAuthenticator implements PasswordAuth {
    @Override
    public boolean authenticateWithPassword(String userId, String password) {
        System.out.println("Authenticating with password...");
        return true;
    }
}

class BiometricAuthenticator implements BiometricAuth {
    @Override
    public boolean authenticateWithBiometrics(String userId) {
        System.out.println("Authenticating with biometrics...");
        return true;
    }
}

class QRCodeAuthenticator implements QRCodeAuth {
    @Override
    public boolean authenticateWithQRCode(String qrCode) {
        System.out.println("Authenticating with QR Code...");
        return true;
    }
}

Enter fullscreen mode Exit fullscreen mode

Typescript

interface PasswordAuth {
  authenticateWithPassword(userId: string, password: string): boolean;
}

interface BiometricAuth {
  authenticateWithBiometrics(userId: string): boolean;
}

interface QRCodeAuth {
  authenticateWithQRCode(qrCode: string): boolean;
}

class PasswordAuthenticator implements PasswordAuth {
  authenticateWithPassword(userId: string, password: string): boolean {
    console.log("Authenticating with password...");
    return true;
  }
}

class BiometricAuthenticator implements BiometricAuth {
  authenticateWithBiometrics(userId: string): boolean {
    console.log("Authenticating with biometrics...");
    return true;
  }
}

class QRCodeAuthenticator implements QRCodeAuth {
  authenticateWithQRCode(qrCode: string): boolean {
    console.log("Authenticating with QR Code...");
    return true;
  }
}
Enter fullscreen mode Exit fullscreen mode

Benefícios da Refatoração

  1. Interfaces específicas: Cada classe implementa apenas os métodos que realmente utiliza.
  2. Flexibilidade: Adicionar novos métodos ou modos de autenticação não impacta implementações existentes.
  3. Manutenção mais simples: Reduz o impacto de mudanças no código, evitando refatorações desnecessárias.

Conclusão

Top comments (0)