Si noti che alcune delle altre risposte potrebbero probabilmente descrivere le fabbriche, ma non descrivere il modello di fabbrica GOF.
Ora voglio sostituire questa linea con un modello fabbrica, anche se non sono sicuro come il mio costruttore TestMode richiede una oggetto in più e non sono sicuro dove mi avrei bisogno di passare questo valore.
Bene, si potrebbe pensare in questo modo: MainMode, non TestMode, è quello che fa una cosa speciale. La cosa speciale che fa, è di ignorare il numero dato, al fine di garantire che sia davvero casuale. In questo modo di pensarci, è MainMode che fa qualcosa in più.
Oppure, se diverso da casualità, MainMode e TestMode non sono diversi, allora si potrebbe pensare che è possibile scomporre tale somiglianza in una classe, a cui viene fornita una delle due Strategie per il calcolo di numeri casuali. Una strategia sarebbe in realtà casuale, e uno sarebbe perverso, con un intervallo casuale di solo 1 valore.
Ma supponiamo che ci siano altre differenze tra MainMode e TestMode - presumibilmente TestMode emette un debugging extra su System.out o qualcosa del genere.
Possiamo ancora fattore fuori "come facciamo forniamo casualità" dal stiamo testando o il gioco per davvero". Queste sono ortogonali preoccupazioni.
Così ora sappiamo che, oltre a qualsiasi altra cosa un "La modalità sì, dovrebbe accettare una strategia di casualità.Poi, ad esempio, quando ti viene detto che la piattaforma standard casuale non è abbastanza casuale, puoi sostituirla con una migliore casuale.
Oppure può fare test dove l'intervallo di randoms è vincolato a due sole scelte, o sempre si alterna da uno a zero, o restituisce su ogni chiamata il valore successivo in qualche Vecrtor o Iterat o.
in modo da utilizzare il modello di strategia CdF per costruire le strategie di casualità:
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(); }
}
Ora, se tutta la vostra applicazione sempre e solo crea uno Mode', non c'è bisogno di una fabbrica; si utilizza una factory quando è necessario creare ripetutamente lo stesso tipo di classe; la fabbrica è in realtà solo una strategia per creare il giusto tipo di (sotto) classe.
Nel codice di produzione, ho utilizzato le fabbriche in cui ho una classe generica che crea elementi e devo dire come creare la sottoclasse giusta da creare; Passo in una fabbrica per farlo.
Ora creiamo un modello di fabbrica per la 'Modalità; questo sarà sorprendentemente simile al modello di strategia:
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);
}
}
Così ora si sa circa il modello di fabbrica e Pattern strategia, e in che modo sono simili in "forma", ma diverso nel modo in cui siamo abituati: Fabbrica Pattern è Object Creation e restituisce un oggetto da utilizzare; La strategia è Object Behavioral e un'istanza viene solitamente creata in modo esplicito e un riferimento all'istanza, per incapsulare un algoritmo. Ma in termini di struttura, sono abbastanza simili.
Modifica: l'OP chiede, in un commento, "Come dovrei integrare questo nella mia GUI?"
Bene, nessuno di questi elementi appartiene alla GUI del programma, tranne forse la "Modalità". Dovresti creare ConcreteStrategy e passarlo alla Factory preferita in alcune routine di setup, possibilmente determinando quale usare in base agli argomenti della riga di comando o ai file di configurazione. in pratica, dovresti selezionare lo stabilimento corretto molto quando selezioni la classe corretta nel tuo post originale. Anche in questo caso, se crei solo uno di questi elementi, non hai bisogno di una Factory; le fabbriche sono destinate alla produzione di massa (o alla creazione di famiglie di tipi concreti correlati - sebbene ciò esuli dallo scopo di questa domanda).
(Supponiamo di avere un gioco in cui l'utente può selezionare sulla riga di comando se combattere robot o draghi, poi vorremmo creare un'istanza di un OpponentFactory che producono avversari (un'interfaccia), con classi derivate RobotOpponent e DragonOpponent e passa quella fabbrica alla parte del gioco che genera NuewOpponent(). Allo stesso modo, un utente potrebbe selezionare avversari coraggiosi o codardi, che avremmo impostato come strategia. Non abbiamo bisogno di creare più istanze di Strategia, come strategia di solito è idempotente (senza stato e 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);
}
Quindi, come dovrei implementarlo nella mia GUI? –