design patterns - pattern - Patrón de diseño para la implementación por defecto con métodos vacíos.
patrones de diseño pdf (9)
¿Estás preguntando sobre el patrón de objeto nulo ?
Además de su edición, el objeto MyClass
no es más que una implementación predeterminada. No creo que haya ningún patrón de diseño particular que lo describa.
¿Existe un patrón de diseño específico que describa el escenario en el que se proporciona una implementación predeterminada no abstracta que implementa todos o algunos de los métodos en la interfaz con implementaciones NO-OP vacías? Esto se hace con la intención de aliviar las subclases con la carga de implementar métodos que ellos mismos pueden no necesitar / usar:
public interface MyInterface {
public void doThis();
public void doThat();
public void done();
}
public class MyClass implements MyInterface {
public void doThis() {
// NO-OP
}
public void doThat() {
// NO-OP
}
public void done() {
// Some standard implementation
}
}
public class MuSubClass extends MyClass {
public void doThat() {
// Subclass only cares about doThat()
}
}
He visto este patrón usado varias veces, incluido el DefaultHandler de Java en el marco de SAX y el MouseAdapter . En algunos casos, estas clases se denominan Adaptadores, pero tuve la impresión de que el patrón del adaptador se traduce entre dos interfaces diferentes.
Dado que en estos casos solo hay una interfaz declarada que se está traduciendo a un subconjunto no definido de esa interfaz, no tengo claro cómo esto es en el espíritu del patrón del adaptador.
Además, tampoco veo cómo esto se adhiere al patrón NullObject , dado que algunos métodos podrían tener una implementación, y el NullObject es tradicionalmente un singleton.
Creo que Martin Fowler llamaría a esto un patrón de objeto nulo. En su libro de Refactorización [1], Martin introduce objetos nulos como tales:
La esencia del polimorfismo es que, en lugar de preguntar a un objeto de qué tipo es y luego invocar algún comportamiento basado en la respuesta, simplemente invoca el comportamiento. El objeto, dependiendo de su tipo, hace lo correcto. Uno de los lugares menos intuitivos para hacer esto es cuando tiene un valor nulo en un campo.
Luego agrega: "Usted se beneficia cuando muchos clientes quieren hacer lo mismo; simplemente pueden confiar en el comportamiento nulo predeterminado". También introduce un método isNull () para clientes que requieren comportamientos variantes.
Estoy de acuerdo en que a veces veo una implementación (a menudo abstracta) llamada adaptador. Por ejemplo, en el marco de Android, AnimatorListenerAdapter (código fuente here ) se describe como:
Esta clase de adaptador proporciona implementaciones vacías de los métodos de Animator.AnimatorListener. Cualquier escucha personalizada que se preocupe solo por un subconjunto de los métodos de esta escucha puede simplemente subclasificar esta clase de adaptador en lugar de implementar la interfaz directamente.
[1] "Refactorización: Mejora del diseño del código existente", Capítulo 9, "Simplificación de expresiones condicionales", "Introducción de objeto nulo".
Debe seguir diferentes principios de diseño: principio de segregación de interfaz
El Principio de Segregación de Interfaz establece que los clientes no deben ser obligados a implementar interfaces que no utilizan. En lugar de una sola interfaz, se prefieren muchas pequeñas interfaces basadas en grupos de métodos, cada uno de los cuales sirve a un submódulo.
No debes implementar MÁS Y no debes implementar MENOS
Echa un vistazo a las preguntas relacionadas de SE para más detalles.
El principio de segregación de interfaz
Principio de Segregación de Interfaz - Programa a una interfaz
Este patrón era frecuente en versiones anteriores de Java. Es la alternativa de Java 7 a los métodos predeterminados en las interfaces .
Josh Bloch lo llama una implementación esquelética . Si bien una implementación esquelética suele ser abstracta, no es necesario forzar a los clientes a crear una subclase si el propio esqueleto es suficiente.
Estoy de acuerdo con la respuesta anterior que señala el Principio de Segregación de Interfaz . La necesidad de una implementación esquelética puede ser un olor de código que indique que una interfaz es demasiado "gruesa" y puede estar intentando hacer más de un trabajo. La división de la interfaz es preferible en este escenario a la creación de una implementación esquelética con lógica ficticia o noop.
Gran pregunta
Comencé a usar NoOp
como un prefijo de nombre de clase para este patrón. Es breve, claro y no está sobrecargado (como ¿ Empty
[no contiene nada?], Null
[¿Patrón de objeto nulo, que es diferente?], Abstract
[¿Proporciona alguna implementación?], O Base
[¿Proporciona alguna implementación?]) .
Puedo escribir este estilo de clase cuando tengo una API de terceros que proporciona "Hooks" para la documentación durante una operación compleja. Considere las siguientes dos clases proporcionadas por una biblioteca:
public class LongRunningActionRunner {
public void runSomethingLong(DecisionListener cdh) {
// ...
}
}
public interface DecisionListener {
public void beforeFooHook();
public void afterFooHook();
public void beforeBarHook();
public void afterBarHook();
public void beforeBazHook();
public void afterBazHook();
}
En este caso, puede corregir una clase usando este patrón como este:
public class NoOpDecisionListener implements DecisionListener {
@Override public Something beforeFooHook() {}
@Override public Something afterFooHook() {}
@Override public Something beforeBarHook() {}
@Override public Something afterBarHook() {}
@Override public Something beforeBazHook() {}
@Override public Something afterBazHook() {}
}
He visto este diseño utilizado en Spring, donde tienen una clase llamada FlowExecutionListenerAdapter que le ahorra la implementación de todas las operaciones FlowExecutionListener.
Sin embargo, suena como el patrón de objeto nulo también. Sin embargo, siento que se siente mejor en el mundo del Adaptador simplemente porque cambia el comportamiento de la interfaz al permitirle solo implementar la parte que desee ... pero es difícil.
Estoy seguro de que esta pregunta se ha hecho antes?
Esto suena similar no? podría valer la pena una lectura.
Para mí, esto parece más cercano al patrón de caso especial u objeto nulo .
Sus actualizaciones sugieren que algo similar al Método de plantilla espera que no tenga un solo método que llame a cada método de plantilla, por ejemplo,
public void doEverything()
{
doThis();
doThat();
done();
}
También se usa en Swing (WindowAdapter, que implementa WindowListener). Es solo un adaptador conveniente, solo tiene que definir 1-2 métodos de esta manera para tener un útil detector de ventanas. Esta es de hecho una instancia del patrón del adaptador, también muestra el poder de las clases abstractas. Incluso es un ejemplo para ilustrar por qué la herencia de implementación múltiple es útil a veces.
En cuanto a los Patrones de Diseño regulares, en el Método Temlate puede definir operaciones de gancho, que pueden ser anuladas (a diferencia de los métodos abstractos, que deben ser), pero el comportamiento predeterminado (generalmente el NO-OP) también es significativo.
No hay patrones de diseño para la implementación por defecto.
Usualmente DoNothing
prefijo DoNothing
al nombre de la clase. Dependiendo de su intención, uso también Base
o Default
(este último es ampliamente utilizado). Probablemente MouseAdapter
debería llamarse DefaultMouseListener
.
En el caso de que le importe, puede apilar sistemáticamente una interfaz con un DynamicProxy simple, debe devolver solo un valor predeterminado "agradable" (nulo para Objeto, 0 para numérico, etc.).
Por cierto esta es una muy buena pregunta.
EDITAR
Además, esto no es ni un Stub ni un Mock : tal vez se pueda confundir con un Stub pero la intención es diferente.