🚀 Revisando o S.O.L.I.D na Prática com Flutter e Dart

Published: (February 25, 2026 at 10:58 PM EST)
3 min read
Source: Dev.to

Source: Dev.to

🎯 Introdução

Resolvi revisar os meus conhecimentos sobre temas essenciais da programação. Iniciei pelo SOLID porque é algo que deve ser revisitado de vez em quando para garantir que estamos entendendo não só o conceito, mas a prática também.

Com isso, podemos escrever códigos mais limpos, escaláveis e de fácil entendimento.

🛠️ Metodologia

Usei como base dois repositórios meus de quando eu estava estudando Clean Architecture. Um deles trata‑se de um app simples: buscar conselhos em uma API e retornar para o usuário.

Neste projeto, aplico cada um dos cinco princípios do SOLID. Abaixo, detalho como cada um deles se comporta no código.

🟢 S — Single Responsibility Principle (SRP)

Princípio da Responsabilidade Única

Uma classe deve ter um, e apenas um, motivo para mudar.

abstract class AdviceRemoteDataSource {
  Future? getAdvice();
}

Outro exemplo claro é o tratamento de erros. Criamos uma estrutura base e especializamos as falhas:

abstract class Failure extends Equatable {
  const Failure([List properties = const []]) : super();
}

// Responsável apenas por erros de servidor
class ServerFailure extends Failure {
  @override
  List get props => [];
}

// Responsável apenas por erros de cache local
class CacheFailure extends Failure {
  @override
  List get props => [];
}

🔵 O — Open/Closed Principle (OCP)

Aberto para Extensão, Fechado para Modificação

Você deve ser capaz de estender o comportamento de uma classe sem modificar o seu código‑fonte original.

abstract class AdviceRepository {
  Future>? getAdvice();
}

class AdviceRepositoryImpl implements AdviceRepository {
  final AdviceRemoteDataSource remoteDataSource;

  AdviceRepositoryImpl({required this.remoteDataSource});

  @override
  Future>? getAdvice() async {
    try {
      final remoteAdvice = await remoteDataSource.getAdvice();
      return Right(remoteAdvice);
    } on ServerException {
      return Left(ServerFailure());
    }
  }
}

🟡 L — Liskov Substitution Principle (LSP)

Princípio da Substituição de Liskov

Objetos de uma superclasse devem ser substituíveis por objetos de suas subclasses sem quebrar a aplicação.

class AdviceRemoteDataSourceImpl implements AdviceRemoteDataSource {
  final http.Client client;
  AdviceRemoteDataSourceImpl({required this.client});

  @override
  Future? getAdvice() async {
    // Implementação real da chamada HTTP
    // ...
  }
}

💡 Obs.: Uma melhoria seria criar um AdviceDataSource genérico, permitindo trocar o Remote pelo Local de forma transparente.

🟠 I — Interface Segregation Principle (ISP)

Segregação de Interface

Uma classe não deve ser forçada a implementar interfaces e métodos que não utiliza.

// Interface específica e focada no domínio de conselhos
abstract class AdviceRemoteDataSource {
  Future? getAdvice();
}

🔴 D — Dependency Inversion Principle (DIP)

Inversão de Dependência

Dependa de abstrações, não de implementações concretas.

void setupLocator() {
  // Registramos a abstração apontando para a implementação
  getIt.registerLazySingleton(
    () => AdviceRepositoryImpl(remoteDataSource: getIt()),
  );

  getIt.registerLazySingleton(
    () => AdviceRemoteDataSourceImpl(client: getIt()),
  );

  getIt.registerLazySingleton(() => http.Client());
}

📊 Resumo Visual

SiglaPrincípioResumo em uma frase
SResponsabilidade ÚnicaCada classe faz apenas uma coisa.
OAberto/FechadoEstenda o comportamento sem alterar o original.
LSubstituição de LiskovSubclasses devem honrar o contrato da base.
ISegregação de InterfaceCrie interfaces pequenas e específicas.
DInversão de DependênciaDependa de contratos, não de classes concretas.

🏁 Conclusão

Utilizar esses conceitos na prática vai além de construir “códigos bonitos”. Trata‑se de garantir a manutenibilidade. Um código bem estruturado permite que ele viva mais e que as manutenções futuras não sejam um sofrimento.

Lembre‑se: o seu código fala muito sobre você! 🚀

0 views
Back to Blog

Related posts

Read more »