Veamos esto prácticamente
Obj 3
ahora sabe que Obj 4
existe. ¿Y qué? ¿Por qué nos importa?
DIP dice
"Los módulos de alto nivel no deberían depender de módulos de bajo nivel. Ambos deberían depender de abstracciones".
Bien, pero, ¿no son todos los objetos abstracciones?
DIP también dice
"Las abstracciones no deberían depender de los detalles. Los detalles deberían depender de las abstracciones".
Bien, pero si mi objeto está correctamente encapsulado, ¿eso no oculta ningún detalle?
A algunas personas les gusta insistir ciegamente en que cada objeto necesita una interfaz de palabras clave. No soy uno de ellos Me gusta insistir ciegamente en que si no los vas a usar ahora, necesitas un plan para lidiar con la necesidad de algo así más adelante.
Si su código es totalmente refactorizable en cada versión, puede extraer las interfaces más adelante si las necesita. Si ha publicado un código que no desea volver a compilar y se encuentra deseando estar hablando a través de una interfaz, necesitará un plan.
Obj 3
sabe Obj 4
existe. ¿Pero Obj 3
sabe si Obj 4
es concreto?
Esto es por qué es tan agradable NO propagarse por new
todas partes. Si Obj 3
no sabe si Obj 4
es concreto, probablemente porque no lo creó, entonces si se coló más tarde y se convirtió Obj 4
en una clase abstracta Obj 3
no le importaría.
Si puedes hacer eso, entonces Obj 4
ha sido completamente abstracto todo el tiempo. Lo único que hace que una interfaz entre ellos desde el principio te dé es la seguridad de que alguien no agregará accidentalmente código que regala que Obj 4
es concreto en este momento. Los constructores protegidos pueden mitigar ese riesgo, pero eso lleva a otra pregunta:
¿Obj 3 y Obj 4 están en el mismo paquete?
Los objetos a menudo se agrupan de alguna manera (paquete, espacio de nombres, etc.). Cuando se agrupan sabiamente, cambian los impactos más probables dentro de un grupo en lugar de entre grupos.
Me gusta agrupar por característica. Si Obj 3
y Obj 4
están en el mismo grupo y capa, es muy poco probable que haya publicado uno y no quiera refactorizarlo mientras necesita cambiar solo el otro. Eso significa que es menos probable que estos objetos se beneficien de tener una abstracción entre ellos antes de que tenga una clara necesidad.
Si está cruzando un límite de grupo, es realmente una buena idea dejar que los objetos en ambos lados varíen independientemente.
Debería ser así de simple, pero desafortunadamente tanto Java como C # han tomado decisiones desafortunadas que complican esto.
En C # es tradición nombrar cada interfaz de palabras clave con un I
prefijo. Eso obliga a los clientes a SABER que están hablando con una interfaz de palabras clave. Eso interfiere con el plan de refactorización.
En Java es tradición usar un mejor patrón de nomenclatura: sin FooImple implements Foo
embargo, esto solo ayuda a nivel de código fuente ya que Java compila interfaces de palabras clave en un binario diferente. Eso significa que cuando se refactoriza Foo
de clientes concretos a abstractos que no necesitan un solo carácter de código cambiado, aún debe volver a compilarse.
Son estos ERRORES en estos idiomas particulares los que evitan que las personas puedan posponer el resumen formal hasta que realmente lo necesiten. No dijo qué idioma está utilizando, pero comprende que hay algunos idiomas que simplemente no tienen estos problemas.
No dijo qué idioma está utilizando, así que lo instaré a que analice su idioma y su situación cuidadosamente antes de que decida que serán interfaces de palabras clave en todas partes.
El principio YAGNI juega un papel clave aquí. Pero también lo hace "Por favor, haz que sea difícil pegarme un tiro en el pie".