Definição
Este princípio foi proposto por Martin Fowler em seu blog.
O princípio nos ajuda a lembrar que orientação a objetos é sobre encapsulamento de dados e sobre operações sobre esses dados. Isso nos lembra que, em vez de solicitar dados a um objeto e agir com base nesses dados, devemos dizer ao objeto o que fazer. Isso incentiva a mover o comportamento para um objeto para acompanhar os dados.
O Problema
Vejamos nosso exemplo abaixo.
Nesse exemplo, temos uma clara violação do encapsulamento e uma não tão clara violação do princípio de responsabilidade única.
Primeiro, a classe ContaService sabe detalhes demais da classe conta, como por exemplo, seu estado interno (saldo), além disso a classe conta service possui duas responsabilidade, realizar uma transferência e de tabela, ela fica responsável por atualizar o saldo de uma ContaBancaria.
Problemas diversos podem acontecer aqui, como por exemplo, concorrência, como saber quem está atualizando o saldo da conta, duplicação, pois cada lugar que o saldo precisar de alteração terá que ter uma código que manipula esse saldo. E o principal , o alto acoplamento entre as classes, ContaService depende da implementação concreta de ContaBancaria.
Suponha que agora tenhamos uma nova classe, ContaEspecial, e essa conta possui um limite de cheque especial.
A classe ContaService teve de ser modificada para que pudesse tratar de ContaEspecial e em todos os locais onde o saldo da conta é manipulado terão de ser modificados também.
A Solução
A class ContaBancaria deve ser responsável por manter seu estado, e não deixá-lo acessível externamente, caso alguma classes queira alterar o estado de ContaBancaria, Essa classe deve dizer isso a ela, ao invés de perguntar qual o estado.
Vamos a nossa refatoração.
Agora, a estado do classe ContaBancaria agora está encapsulado e ContaBancariaService não mais tem conhecimento desse estado.
Desse modo para realizar uma qualquer operação que altere o estado de de ContaBancária, nós devemos dizer isso explicitamente a ela, que pode escolher como proceder.
ContaService ainda estamos “perguntando” a classe ContaBancaria se a operação pode ser realizada, mas ContaService não tem a menor idéia do real estado da de ContaBancaria, ao invés de pedir o estado, ContaService apenas pergunta se a operação pode ser realizada, e então, diz a ContaBancaria para realizar a operação. Uma outra maneira de tratar isso, é apenas mandar ContaBancaria realizar a operação e aguarda o resultado.
Agora ContaService diz explicitamente para ContaBancaria transferir um valor, sem saber qual o estado inicial ou final de ContaBancaria.
O acoplamento ficou bem baixo, pois ContaService só precisa saber que ContaBancaria tem um método transferirPara. Ou seja, ContaService depende da abstração (Interface) de ContaBancaria.
Agora vamos ao Exemplo utilizando ContaEspecial, que possui regras diferentes para retiradas.
Agora nós adicionamos ContaEspecial, que possui uma regras diferentes e não precisamos alterar NADA em ContaService.
Conclusão
Perguntar o estado interno de objetos fere o encapsulamento de aumenta o acoplamento entre classes, além disso, ao obter o estado de uma classe, provavelmente a classe consumidora irá querer tomar alguma ação, que provavelmente será de sua responsabilidade, reduzindo a coesão.