SOLID: princípios, 5 regras de POO e aplicação no desenvolvimento

Autor: IT Sectr Publicado: 2026-05-11 Tempo de leitura: 10 min

SOLID — cinco princípios de programação orientada a objetos formulados por Robert C. Martin (Uncle Bob) no início dos anos 2000. De acordo com a DigitalOcean, 2024, SOLID significa Single Responsibility, Open-Closed, Liskov Substitution, Interface Segregation e Dependency Inversion. Esses princípios formam a base da Clean Architecture e são aplicados no desenvolvimento Android (MVP, MVVM, Clean Architecture) e iOS (VIPER, TCA).

Principais conclusões

  • SOLID — acrônimo de cinco princípios POO: SRP, OCP, LSP, ISP, DIP, formulados por Robert C. Martin para criar código flexível e sustentável.
  • SRP (Single Responsibility) — cada classe tem uma razão para mudar, uma responsabilidade por módulo.
  • OCP (Open-Closed) — classes são abertas para extensão mas fechadas para modificação, implementado através de herança e polimorfismo.
  • LSP (Liskov Substitution) — objetos de subclasses devem substituir objetos da classe base sem alterar a correção do programa.
  • ISP (Interface Segregation) — clientes não devem depender de interfaces que não usam, interfaces devem ser estreitas e específicas.
  • DIP (Dependency Inversion) — módulos de alto nível não dependem de módulos de baixo nível, ambos dependem de abstrações.

O que é SOLID? Visão geral dos cinco princípios

SOLID — acrônimo mnemônico que representa cinco princípios de design orientado a objetos. O termo foi introduzido por Robert C. Martin no artigo «Design Principles and Design Patterns» (2000) e posteriormente popularizado no livro «Agile Software Development: Principles, Patterns, and Practices» (2002). SOLID não é um framework ou biblioteca — é um conjunto de práticas que tornam o código menos acoplado, mais testável e fácil de modificar.

De acordo com Clean Coder Blog, 2014, cada princípio SOLID resolve um problema de design específico: SRP combate classes God, OCP previne mudanças em cascata, LSP protege contra herança incorreta, ISP evita interfaces grandes e DIP reduz o acoplamento forte. Juntos formam a base da Clean Architecture, que é usada em projetos Android com MVP, MVVM e MVI.

SRP: Princípio da Responsabilidade Única

Single Responsibility Principle (SRP) — princípio da responsabilidade única. A formulação: «Uma classe deve ter apenas uma razão para mudar». Isso significa que cada módulo ou classe é responsável por exatamente uma funcionalidade ou uma entidade de domínio. Se uma classe gerencia tanto usuários quanto envio de emails — ela tem duas razões para mudar, violando SRP.

De acordo com Robert C. Martin, 2002, SRP é o princípio mais importante e ao mesmo tempo o mais violado. No desenvolvimento móvel, SRP é frequentemente violado em Activity/Fragment ao combinar lógica de UI, navegação, rede e lógica de negócios. A solução é extrair cada camada em uma classe separada: ViewModel para lógica de UI, Repository para dados, NavController para navegação.

Exemplo SRP: Decompondo UserManager

Considere a classe UserManager, que carrega um perfil, salva configurações e envia emails. São três responsabilidades distintas, cada uma deve ser extraída em uma classe separada: UserProfileRepository (carregamento), UserSettingsStorage (salvamento) e EmailService (envio). O código cliente (ViewModel) usa as três através de Dependency Injection, e cada classe é facilmente testada isoladamente e muda sem afetar as outras.

kotlin
// ❌ Violação SRP: Activity conhece rede, BD e UI
class ProfileActivity : AppCompatActivity() {
    fun loadProfile() {
        api.getUser() // Chamada de rede
        db.saveUser()    // Operação de BD
        updateUI()         // Atualização de UI
    }
}

// ✅ SRP cumprido: camadas estão separadas
class ProfileViewModel : ViewModel() {
    private val repo = UserRepository()
    fun loadProfile() { repo.getUser() }
}

Sinais de violação de SRP: uma classe com mais de 200 linhas, métodos de diferentes domínios, mudanças frequentes por razões diferentes. Para desenvolvimento Android, a regra é simples: Activity lida apenas com o ciclo de vida da tela, ViewModel lida com o estado da UI, Repository lida com fontes de dados.

SRP e Arquitetura de Microsserviços

O princípio SRP se aplica não apenas a classes mas também à arquitetura de nível de serviço. Cada microsserviço lida com uma entidade de domínio: UserService — apenas usuários, PaymentService — apenas pagamentos, NotificationService — apenas notificações. Isso permite escalar, implantar e testar serviços de forma independente. Em aplicativos móveis, SRP no nível de microsserviços se manifesta na separação de clientes API por domínio.

OCP: Princípio Aberto/Fechado

Open-Closed Principle (OCP) — classes devem estar abertas para extensão (novo comportamento pode ser adicionado) e fechadas para modificação (código existente não é alterado). Isso é alcançado através de polimorfismo, classes abstratas e interfaces. Em vez de adicionar if-else a um método existente, uma nova implementação de interface é criada.

De acordo com Clean Coder Blog, 2014, OCP funciona melhor com o padrão Strategy. Por exemplo, se um aplicativo suporta diferentes métodos de pagamento (Google Pay, Apple Pay, PayPal), não é necessário adicionar um switch-case ao processador de pagamentos. Cada método de pagamento implementa uma interface comum PaymentGateway, e um novo sistema de pagamento é adicionado como uma nova classe sem modificar as existentes.

kotlin
// ✅ OCP: aberto para extensão, fechado para modificação
interface PaymentGateway {
    fun processPayment(amount: Double): Boolean
}

class GooglePayGateway : PaymentGateway {
    override fun processPayment(amount: Double) = true
}

// Novo sistema de pagamento — sem alterar código existente
class ApplePayGateway : PaymentGateway {
    override fun processPayment(amount: Double) = true
}

LSP: Princípio da Substituição de Liskov

Liskov Substitution Principle (LSP) — princípio de substituição de Barbara Liskov. Se S é um subtipo de T, então objetos do tipo T podem ser substituídos por objetos do tipo S sem alterar as propriedades do programa. Formalmente: uma função que usa uma classe base deve funcionar corretamente com qualquer uma de suas subclasses. Se uma subclasse lança uma exceção onde a classe base não lança — LSP foi violado.

De acordo com Robert C. Martin, 2002, LSP é o princípio SOLID mais difícil de entender. O exemplo clássico de violação é a classe Square herdando de Rectangle. Se setWidth em Square define tanto largura quanto altura, o código cliente que espera comportamento de Rectangle obtém um resultado inesperado. No desenvolvimento móvel, LSP é frequentemente violado ao herdar ViewModel — quando uma ViewModel filha adiciona dependências obrigatórias.

kotlin
// ❌ Violação LSP: Square quebra o comportamento de Rectangle
open class Rectangle(open var width: Int, open var height: Int)

class Square(side: Int) : Rectangle(side, side) {
    override var width
        get() = super.width
        set(value) { super.setBoth(value, value) }
}

ISP: Princípio da Segregação de Interfaces

Interface Segregation Principle (ISP) — clientes não devem depender de interfaces que não usam. Em vez de uma única interface «gorda», crie várias interfaces estreitas e especializadas. Se uma classe implementa uma interface mas alguns métodos lançam UnsupportedOperationException ou ficam vazios — é um sinal claro de violação de ISP.

De acordo com DigitalOcean, 2024, ISP é especialmente relevante no desenvolvimento móvel ao projetar ViewModel e Repository. Em vez de uma única interface UserRepository com todos os métodos CRUD, é melhor criar QueryUserRepository (somente leitura) e CommandUserRepository (escrita). Então um cliente somente leitura (elemento UI) depende apenas da interface Query e não sabe nada sobre métodos de escrita.

kotlin
// ❌ Interface grande — cliente é forçado a implementar métodos desnecessários
interface UserOperations {
    fun getUser(id: String): User
    fun saveUser(user: User)
    fun deleteUser(id: String)
    fun exportUsers(): File
}

// ✅ ISP: interfaces segregadas
interface UserReader { fun getUser(id: String): User }
interface UserWriter { fun saveUser(user: User) }
interface UserDeleter { fun deleteUser(id: String) }

DIP: Princípio da Inversão de Dependências

Dependency Inversion Principle (DIP) — módulos de alto nível não devem depender de módulos de baixo nível. Ambos devem depender de abstrações (interfaces). Abstrações não devem depender de detalhes — detalhes devem depender de abstrações. Isso não é «Dependency Injection» (DI), embora DI seja uma forma comum de implementar DIP.

De acordo com Robert C. Martin, 2019, DIP é a base da Clean Architecture. ViewModel (alto nível) não deve criar diretamente uma instância de RetrofitApi (detalhe). Em vez disso, ViewModel depende de uma interface UserRepository, e a implementação concreta UserRepositoryImpl com Retrofit é passada através do construtor. No Android, DIP é implementado através de Hilt/Dagger ou Koin: todas as dependências são fornecidas através do contêiner DI.

kotlin
// ✅ DIP: Module depende de abstração, não de detalhes
class UserRepositoryImpl(
    private val api: UserApi,   // Depende da interface
    private val db: UserDao     // Depende da interface
) : UserRepository {

    override suspend fun getUser(id: String): User {
        return api.fetchUser(id)
    }
}

// Hilt DI: detalhes são conectados através do módulo DI
@Module
object NetworkModule {
    @Provides
    fun provideUserApi(retrofit: Retrofit): UserApi =
        retrofit.create(UserApi::class.java)
}

Aplicação de SOLID no desenvolvimento móvel

SOLID no desenvolvimento móvel é aplicado em todos os níveis: da arquitetura do aplicativo a classes individuais. Em projetos Android, Clean Architecture divide o código em três camadas: domain (lógica de negócios — independente de frameworks), data (repositórios, API, BD) e presentation (UI, ViewModel). A camada domain usa princípios SOLID: casos de uso (SRP), interfaces de repositório (DIP), classes de entidade (OCP + LSP).

De acordo com Android Developers Guide, 2025, SRP no Android se manifesta na separação de ViewModel, Repository e Mapper. OCP — ao adicionar novas fontes de dados através da interface DataSource. LSP — no tratamento uniforme de Result em diferentes repositórios. ISP — na abordagem CQRS (separação de repositórios Read/Write). DIP — através de Hilt/Koin para injeção de dependências.

PrincípioProblema sem eleSolução em projeto móvel
SRPActivity com 1000+ linhasViewModel + UseCase + Repository
OCPswitch-case por tipo de pagamentoStrategy: interface PaymentGateway
LSPErro ao substituir BaseViewModelVerificar contrato de subclasses
ISPUnsupportedOperationExceptionSeparação Reader / Writer
DIPViewModel cria Retrofit manualmenteContêiner DI Hilt / Koin

Erros comuns ao aplicar SOLID

Erros de SOLID geralmente estão relacionados à sobrecomplicação excessiva do código. O primeiro — seguir os princípios literalmente sem considerar o contexto. Dividir uma classe UserService em 10 interfaces e 15 classes apenas para um ISP «limpo» é superengenharia. SOLID é uma ferramenta, não um objetivo. O segundo erro — confundir SRP com «um método = uma responsabilidade». Uma classe pode ter vários métodos se todos pertencerem à mesma área de responsabilidade.

De acordo com Simple Thread, 2024, o terceiro erro — ignorar LSP ao herdar ViewModel no Android. Se a ViewModel base espera LiveData mas a filha usa StateFlow — o código cliente inscrito no LiveData não receberá atualizações. O quarto — violar DIP por causa de testes: RepositoryImpl cria diretamente uma instância de OkHttpClient, impossibilitando testes unitários.

A regra de ouro: aplique SOLID quando resolver um problema real (mudanças frequentes, dificuldade de teste, duplicação). Para telas CRUD simples, a aderência estrita a todos os cinco princípios é excessiva. Para lógica de negócios, cálculos financeiros e interações com API, SOLID é essencial.

Conexão entre SOLID e Clean Architecture

Clean Architecture (Robert C. Martin, 2012) — aplicação direta de SOLID no nível de camadas do aplicativo. SRP define os limites dos casos de uso (cada caso de uso — uma classe). OCP é implementado através de interfaces de repositório (Data Layer pode mudar sem modificar Domain). ISP fornece separação do caso de uso em limites de entrada/saída. DIP — direção das dependências para dentro da camada Domain. LSP garante que qualquer implementação de repositório seja substituível sem quebrar os casos de uso.

Perguntas frequentes

O que é SOLID em palavras simples?

SOLID — cinco regras para escrever código fácil de mudar, testar e entender. Cada letra é um princípio: não escreva classes grandes (SRP), não mude código existente — adicione novo (OCP), não quebre o comportamento das subclasses (LSP) e outros.

Qual princípio SOLID é o mais importante?

SRP (Single Responsibility) é considerado o mais importante porque sua violação leva a God classes — classes enormes difíceis de testar e modificar. No entanto, sem DIP (Dependency Inversion) o código permanece fortemente acoplado, o que também é crítico.

SOLID é obrigatório para desenvolvimento móvel?

Não é obrigatório, mas é altamente recomendado para projetos comerciais com ciclo de vida longo. Para aplicativos simples (uma tela, sem lógica de negócios), SOLID pode ser excessivo. Para projetos com 50+ telas e 3+ desenvolvedores, SOLID é o mínimo necessário.

O que acontece se não seguir SOLID?

Consequências: as classes ficam «gordas» (1000+ linhas), uma mudança em um lugar quebra três outros, é impossível escrever testes unitários, adicionar uma nova funcionalidade leva semanas em vez de dias. Com o tempo, o código se torna um «Big Ball of Mud» — emaranhado e frágil.

Como verificar se SOLID está sendo seguido em um projeto?

Sinais de conformidade: cada classe tem menos de 200 linhas, alterar uma funcionalidade não afeta 5+ arquivos, testes podem ser escritos sem simular 10 dependências, um novo desenvolvedor entende a estrutura em um dia. Ferramentas como SonarQube e detekt ajudam a identificar violações de SRP e DIP.

Resumo

  • SOLID — cinco princípios POO (SRP, OCP, LSP, ISP, DIP) para criar código flexível e sustentável
  • SRP — cada entidade é responsável por uma tarefa, resolve o problema de God classes
  • OCP — extensão através de polimorfismo, não modificação de código existente
  • LSP — subclasses não devem quebrar o comportamento da classe base
  • ISP — interfaces estreitas em vez de «canivetes suíços» universais
  • DIP — dependência de abstrações, injeção através de Hilt/Koin no Android
  • SOLID é essencial para Clean Architecture e projetos móveis comerciais

Vamos desenvolver um aplicativo móvel chave na mão

A IT Sectr cria aplicativos para iOS e Android para startups e empresas desde 2017. Nós vamos aconselhá-lo e propor a melhor solução.

Discutir o projeto

Leia também