Tenga en cuenta que algunas de las otras respuestas pueden describir fábricas, pero no describen GOF Factory Pattern.
Ahora quiero reemplazar esta línea con un patrón fábrica, aunque estoy seguro de que mi constructor TestMode requiere una objeto extra y estoy seguro de que me tendría que pasar este valor.
Bueno, podría pensarlo de esta manera: MainMode, no TestMode, es el que hace algo especial. Lo especial que hace es ignorar el número dado, para garantizar que sea realmente aleatorio. De esta manera de pensarlo, es MainMode el que hace algo extra.
O, si además de la aleatoriedad, MainMode y TestMode no son diferentes, entonces estaría pensando quizás que puede restar importancia a esa similitud en una clase, que se proporciona una de dos estrategias para calcular números aleatorios. Una estrategia sería en realidad aleatoria, y una sería perversa, con un rango aleatorio de solo 1 valor.
Pero supongamos que existen otras diferencias entre MainMode y TestMode: presumiblemente TestMode genera una depuración adicional a System.out o algo así.
Todavía podemos factorizar "¿cómo suministramos aleatoriedad" de que estamos probando o jugar el juego de verdad". Estos son ortogonales preocupaciones.
Así que ahora sabemos que, además de cualquier otra cosa que una 'Modo sí, debería aceptar una estrategia de aleatoriedad. Entonces podríamos, por ejemplo, cuando te digan que la plataforma estándar aleatoria no es lo suficientemente aleatoria, puedes reemplazarla por una mejor aleatoria.
O tú puede hacer pruebas donde el rango de randoms está restringido a solo dos opciones, o siempre alterna de uno a cero, o devuelve en cada llamada el siguiente valor en algún Vecrtor o Iterat o.
por lo que utilizar el patrón de estrategia GOF para construir las estrategias de aleatoriedad:
interface RandomStrategy {
public double random();
}
public class NotSoRandom implements RandomStrategy {
private double r;
public NotSoRandom(final double r) { this.r = r; }
public double random() { return r; }
}
public class PlatformRandom implements RandomStrategy {
public double random() { return Math.random(); }
}
Ahora, si todo tu aplicación sólo crea siempre una Mode', no hay necesidad de una fábrica; usa una fábrica cuando necesita crear el mismo tipo de clase una y otra vez; la fábrica es, de hecho, solo una estrategia para crear el tipo correcto de (sub) clase.
En el código de producción, he usado fábricas donde tengo una clase genérica que crea cosas, y necesito decir cómo crear la subclase correcta para crear; Paso en una fábrica para hacer eso.
Ahora creamos un patrón de Fábrica para el 'Modo; esto va a ser sorprendentemente similar al patrón de la estrategia:
abstract class Mode() {
private RandomStrategy r;
public Mode(final RandomStrategy r) { this.r = r; }
// ... all the methods a Mode has
}
public class MainMode implements Mode {
public MainMode(final RandomStrategy r) { super(r); }
}
public class TestMode implements Mode {
public TestMode(final RandomStrategy r) { super(r); }
}
interface ModeFactory{
public Mode createMode(final RandomStrategy r);
}
public class MainFactory() {
public Mode createMode(final RandomStrategy r) {
return new MainMode(r);
}
}
public class TestFactory() {
public Mode createMode(final RandomStrategy r) {
return new TestMode(r);
}
}
Así que ya saben acerca del patrón de la fábrica y el patrón de estrategia, y cómo son similares en "forma", pero diferentes en cómo se usan: Fábrica El patrón es Object Creational y devuelve un objeto para ser utilizado; La estrategia es Object Behavioral, y una instancia generalmente se crea explícitamente y se mantiene una referencia a la instancia, para encapsular un algoritmo. Pero en términos de la estructura, son bastante similares.
Editar: el OP pregunta, en un comentario, "¿Cómo podría integrar esto en mi GUI?"
Bueno, nada de esto pertenece a la GUI de su programa, excepto posiblemente el 'Modo'. Debería crear ConcreteStrategy y pasarlo a la Factory preferida en alguna rutina de configuración, posiblemente determinando cuál usar según los argumentos de la línea de comando o los archivos de configuración. básicamente, seleccionarías la fábrica correcta en la misma medida que seleccionas la clase correcta en tu publicación original. Nuevamente, si solo creas algo, no necesitas una fábrica; las fábricas son para producción en masa (o para crear familias de tipos de concreto relacionados, aunque eso está más allá del alcance de esta pregunta).
(Supongamos que tenemos un juego donde el usuario puede seleccionar en la línea de comandos si luchar contra robots o dragones, entonces quisiéramos crear una OpponentFactory que produzca oponentes (una interfaz), con clases derivadas RobotOpponent y DragonOpponent , y pasar esa fábrica a la parte del juego que engendra aNewOpponent(). De forma similar, un usuario puede seleccionar oponentes valientes o cobardes, que nosotros configuraríamos como una Estrategia. No necesitamos hacer más instancias de Estrategia, como estrategia se suele idempotente (sin estado y Singleton).)
static int main(String[] args) {
// setup game world
final RandomStrategy r = "random".equals(args[0])
? new PlatformRandom() : new NotSoRandom(Integer.intValue(args[0])) ;
// notice the simlarity to the code you originally posted;
// we factored out how to achieve "randomness" as a Strategy.
// now we will use our Strategy to setup our Factory;
final ModeFactory f = "test".equals(args[1])
? new TestFactory(r) : new MainFactory(r);
// also similar to your code
// we've just added an extra level of indirection:
// instead of creating a Mode, we've created an object that can create Modes
// of the right derived type, on demand.
// call something that uses our factory
functionThatRunsameAndNeedstoProduceModesWhenevertNeedsTo(f);
}
Entonces, ¿cómo implementaría esto en mi GUI? –