Ambas respuestas actuales parecen dar solo en el blanco, y se centran en ejemplos que nublan la idea central. Esto tampoco es (únicamente) un principio de OOP sino un principio de diseño de software en general.
Lo que "varía" en esta frase es el código. Christophe está a punto de decir que generalmente es algo que puede variar, es decir, a menudo lo anticipa . El objetivo es protegerse de futuros cambios en el código. Esto está estrechamente relacionado con la programación en una interfaz . Sin embargo, Christophe es incorrecto al limitar esto a "detalles de implementación". De hecho, el valor de este consejo a menudo se debe a cambios en los requisitos .
Esto solo está indirectamente relacionado con el estado de encapsulación, que es lo que creo que está pensando David Arno. Este consejo no siempre (pero a menudo lo hace) sugiere un estado encapsulado, y este consejo se aplica también a los objetos inmutables. De hecho, simplemente nombrar constantes es una forma (muy básica) de encapsular lo que varía.
CandiedOrange combina explícitamente "lo que varía" con "detalles". Esto es solo parcialmente correcto. Estoy de acuerdo en que cualquier código que varía es "detalles" en algún sentido, pero un "detalle" puede no variar (a menos que defina "detalles" para hacer esto tautológico). Puede haber razones para encapsular detalles que no varían, pero este dictamen no es uno. Hablando en términos generales, si estaba muy seguro de que "perro", "gato" y "pato" serían los únicos tipos con los que tendría que tratar, entonces este dictamen no sugiere la refactorización de CandiedOrange.
Casting del ejemplo de CandiedOrange en un contexto diferente, suponga que tenemos un lenguaje de procedimiento como C. Si tengo algún código que contenga:
if (pet.type() == dog) {
pet.bark();
} else if (pet.type() == cat) {
pet.meow();
} else if (pet.type() == duck) {
pet.quack()
}
Puedo esperar razonablemente que este código cambie en el futuro. Puedo "encapsularlo" simplemente definiendo un nuevo procedimiento:
void speak(pet) {
if (pet.type() == dog) {
pet.bark();
} else if (pet.type() == cat) {
pet.meow();
} else if (pet.type() == duck) {
pet.quack()
}
}
y usar este nuevo procedimiento en lugar del bloque de código (es decir, una refactorización de "método de extracción") En este punto, agregar un tipo de "vaca" o lo que sea, solo requiere actualizar el speak
procedimiento. Por supuesto, en un lenguaje OO, en su lugar, puede aprovechar el despacho dinámico como se alude a la respuesta de CandiedOrange. Esto sucederá naturalmente si accede a pet
través de una interfaz. La eliminación de la lógica condicional a través del despacho dinámico es una preocupación ortogonal que fue parte de por qué hice esta representación procesal. También quiero enfatizar que esto no requiere características particulares de OOP. Incluso en un lenguaje OO, encapsular lo que varía no significa necesariamente que deba crearse una nueva clase o interfaz.
Como un ejemplo más arquetípico (que está más cerca pero no del todo OO), digamos que queremos eliminar los duplicados de una lista. Digamos que lo implementamos iterando sobre la lista haciendo un seguimiento de los elementos que hemos visto hasta ahora en otra lista y eliminando cualquier elemento que hayamos visto. Es razonable suponer que es posible que queramos cambiar la forma en que hacemos un seguimiento de los elementos vistos por, al menos, razones de rendimiento. El dictamen para encapsular lo que varía sugiere que deberíamos construir un tipo de datos abstractos para representar el conjunto de elementos vistos. Nuestro algoritmo ahora se define en contra de este tipo de conjunto de datos abstracto, y si decidimos cambiar a un árbol de búsqueda binario, nuestro algoritmo no necesita cambiar ni importar. En un lenguaje OO, podemos usar una clase o interfaz para capturar este tipo de datos abstractos. En un lenguaje como SML / O '
Para un ejemplo basado en requisitos, supongamos que necesita validar algún campo con respecto a alguna lógica empresarial. Si bien es posible que ahora tenga requisitos específicos, sospecha que evolucionarán. Puede encapsular la lógica actual en su propio procedimiento / función / regla / clase.
Aunque esta es una preocupación ortogonal que no forma parte de "encapsular lo que varía", a menudo es natural abstraerse, es decir, parametrizarse por la lógica ahora encapsulada. Esto generalmente conduce a un código más flexible y permite cambiar la lógica al sustituir en una implementación alternativa en lugar de modificar la lógica encapsulada.