Ambas as respostas atuais parecem atingir apenas parcialmente a marca e se concentram em exemplos que obscurecem a idéia central. Este também não é (apenas) um princípio de POO, mas um princípio de design de software em geral.
O que está "variando" nesta frase é o código. Christophe está certo ao dizer que geralmente é algo que pode variar, ou seja, você costuma antecipar isso. O objetivo é proteger-se de futuras alterações no código. Isso está intimamente relacionado à programação em uma interface . No entanto, Christophe está incorreto ao limitar isso a "detalhes de implementação". De fato, o valor desse conselho geralmente é devido a alterações nos requisitos .
Isso está indiretamente relacionado ao estado de encapsulamento, que é o que eu acredito que David Arno está pensando. Esse conselho nem sempre (mas geralmente o sugere) sugere um estado de encapsulamento e também se aplica a objetos imutáveis. De fato, apenas nomear constantes é uma forma (muito básica) de encapsular o que varia.
CandiedOrange confunde explicitamente "o que varia" com "detalhes". Isso está apenas parcialmente correto. Concordo que qualquer código que varie seja "detalhes" em algum sentido, mas um "detalhe" pode não variar (a menos que você defina "detalhes" para tornar isso tautológico). Pode haver razões para encapsular detalhes não variáveis, mas esse ditado não é um deles. Grosso modo, se você estava altamente confiante de que "cachorro", "gato" e "pato" seriam os únicos tipos com os quais você precisaria lidar, esse ditado não sugere a refatoração que o CandiedOrange realiza.
Fundindo o exemplo de CandiedOrange em um contexto diferente, suponha que tenhamos uma linguagem processual como C. Se eu tiver algum código que contenha:
if (pet.type() == dog) {
pet.bark();
} else if (pet.type() == cat) {
pet.meow();
} else if (pet.type() == duck) {
pet.quack()
}
Posso razoavelmente esperar que esse pedaço de código mude no futuro. Eu posso "encapsular" simplesmente definindo um novo procedimento:
void speak(pet) {
if (pet.type() == dog) {
pet.bark();
} else if (pet.type() == cat) {
pet.meow();
} else if (pet.type() == duck) {
pet.quack()
}
}
e usando esse novo procedimento em vez do bloco de código (ou seja, uma refatoração de "método de extração"). Neste ponto, adicionar um tipo de "vaca" ou o que requer apenas a atualização do speak
procedimento. Obviamente, em um idioma OO, você pode aproveitar o envio dinâmico, como aludido pela resposta de CandiedOrange. Isso acontecerá naturalmente se você acessar pet
através de uma interface. A eliminação da lógica condicional via despacho dinâmico é uma preocupação ortogonal, que foi parte do motivo pelo qual fiz essa versão processual. Também quero enfatizar que isso não requer recursos específicos do OOP. Mesmo em uma linguagem OO, encapsular o que varia não significa necessariamente que uma nova classe ou interface precise ser criada.
Como um exemplo mais arquetípico (que é mais próximo, mas não exatamente do OO), digamos que queremos remover as duplicatas de uma lista. Digamos que implementamos iterando a lista, mantendo o controle dos itens que vimos até agora em outra lista e removendo os itens que vimos. É razoável supor que podemos querer mudar a maneira como mantemos o controle dos itens vistos, por pelo menos por razões de desempenho. O ditado para encapsular o que varia sugere que devemos construir um tipo de dados abstrato para representar o conjunto de itens vistos. Nosso algoritmo agora está definido nesse tipo de dados abstrato Set e, se decidirmos mudar para uma árvore de pesquisa binária, nosso algoritmo não precisará ser alterado ou importado. Em uma linguagem OO, podemos usar uma classe ou interface para capturar esse tipo de dado abstrato. Em um idioma como SML / O '
Para um exemplo orientado a requisitos, diga que você precisa validar algum campo com relação a alguma lógica de negócios. Embora você possa ter requisitos específicos agora, você suspeita fortemente que eles irão evoluir. Você pode encapsular a lógica atual em seu próprio procedimento / função / regra / classe.
Embora essa seja uma preocupação ortogonal que não faz parte de "encapsular o que varia", muitas vezes é natural abstrair, que é parametrizado pela lógica agora encapsulada. Isso normalmente leva a um código mais flexível e permite que a lógica seja alterada substituindo em uma implementação alternativa em vez de modificar a lógica encapsulada.