El siguiente ejemplo de código es una implementación del patrón de estrategia copied from Wikipedia. Mi pregunta completa que sigue ...¿Este patrón de estrategia Java tiene una clase de contexto redundante?
main
El método del Wiki:
//StrategyExample test application
class StrategyExample {
public static void main(String[] args) {
Context context;
// Three contexts following different strategies
context = new Context(new ConcreteStrategyAdd());
int resultA = context.executeStrategy(3,4);
context = new Context(new ConcreteStrategySubtract());
int resultB = context.executeStrategy(3,4);
context = new Context(new ConcreteStrategyMultiply());
int resultC = context.executeStrategy(3,4);
}
}
Las piezas del patrón:
// The classes that implement a concrete strategy should implement this
// The context class uses this to call the concrete strategy
interface Strategy {
int execute(int a, int b);
}
// Implements the algorithm using the strategy interface
class ConcreteStrategyAdd implements Strategy {
public int execute(int a, int b) {
System.out.println("Called ConcreteStrategyA's execute()");
return a + b; // Do an addition with a and b
}
}
class ConcreteStrategySubtract implements Strategy {
public int execute(int a, int b) {
System.out.println("Called ConcreteStrategyB's execute()");
return a - b; // Do a subtraction with a and b
}
}
class ConcreteStrategyMultiply implements Strategy {
public int execute(int a, int b) {
System.out.println("Called ConcreteStrategyC's execute()");
return a * b; // Do a multiplication with a and b
}
}
// Configured with a ConcreteStrategy object and maintains a reference to a Strategy object
class Context {
private Strategy strategy;
// Constructor
public Context(Strategy strategy) {
this.strategy = strategy;
}
public int executeStrategy(int a, int b) {
return strategy.execute(a, b);
}
}
teniendo especialmente en cuenta el ejemplo anterior, es la clase Context
redundante?
Por ejemplo, puedo obtener la siguiente implementación alternativa de main
utilizando las clases y la interfaz existentes excepto Context y funcionará exactamente igual. Todavía está débilmente acoplado.
((Editar:? En este escenario simple, cuando salgo de la clase Context, voy a estar haciendo un futuro error))
public static void main(String[] args) {
IStrategy strategy;
// Three strategies
strategy = new ConcreteStrategyAdd();
int resultA = strategy.executeStrategy(3,4);
strategy = new ConcreteStrategySubtract();
int resultB = strategy.executeStrategy(3,4);
strategy = new ConcreteStrategyMultiply();
int resultC = strategy.executeStrategy(3,4);
}
cotización Actualizar
Listado en forma de punto lo que se descubrió a través de respuestas y comentarios:
- El contexto permite la variación en cómo se usa la estrategia compuesta (p. tiempo de su llamada). Diferentes contextos pueden hacer un trabajo interno diferente antes y después de llamar a la estrategia dada.
- El contexto es un "cuadro negro" de alto nivel. La lógica de Contexto puede cambiar, también la Estrategia compuesta puede cambiar (o usarse una diferente) sin romper el cliente porque el cliente solo entiende cómo llamar al contexto.
- Aunque creé una implementación alternativa del código de muestra de Wikipedia al omitir el contexto, y aunque funcionaba igual que el original, la situación se simplificó (en ambos casos) y mis cambios realmente significaron: 1. es ya no es un patrón de Estrategia, 2. Extraño los beneficios del espíritu del patrón de Estrategia que se mencionan aquí.
- Mi implementación alternativa usó el método principal como un contexto, así que también podría mantener el contexto si lo simula de manera efectiva. Al crear un patrón de estrategia impuro, se creó confusión. No necesité reinventar la rueda o intentar ser más inteligente (en este caso).
Si algún otro punto fuera útil o si necesita corrección, deje un comentario y modificaré la lista en consecuencia.
Esta es una explicación completamente detallada que describe claramente la importancia del contexto, incluida la muestra de código de apoyo. Estupendo. –
Supongo, además, que una clase de contexto se puede subclasificar para agregar comportamiento al trabajo de contexto base (es decir, volver a llamar al procesamiento de contexto base primero antes de realizar su trabajo adicional). Lo mismo podría hacerse con cualquier estrategia concreta. Esto permitiría que las partes varíen el comportamiento de manera independiente, pero que sean compatibles con los tipos básicos. Así que estoy empezando a darme cuenta de que hay mucha flexibilidad tanto horizontalmente mediante implementaciones alternativas como verticalmente a través de la herencia, y también combinaciones de ellas. Interesante. Las cosas también pueden complicarse rápidamente si no se las piensa. –
Hmm. No estoy seguro de que me guste la idea de un 'Contexto' polimórfico. OMI, sería mejor componer las diferentes piezas en un solo 'Contexto' coherente, y luego tener las estrategias apropiadas para cada uno según corresponda. –