Domanda

Uno dei modi per implementare correttamente la Dependency Injection è quello di separare la creazione di oggetti dalla logica aziendale. In genere, ciò implica l'utilizzo di Factory per la creazione di oggetti.

Fino a questo punto, non ho mai preso in seria considerazione l'utilizzo di una Factory, quindi mi scuso se questa domanda sembra un po 'semplicistica:

In tutti gli esempi del modello di fabbrica che ho incontrato, vedo sempre esempi molto semplici che non hanno parametri. Ad esempio, ecco una Factory rubata da di Misko Hevery eccellente How To Think About " new " Operatore articolo.

class ApplicationBuilder {
  House build() {
    return new House(new Kitchen(
               new Sink(),
               new Dishwasher(),
               new Refrigerator())
           );
  }
}

Tuttavia, cosa succede se voglio che ogni casa che costruisco abbia un nome? Sto ancora usando il modello Factory se riscrivo questo codice come segue?

class ApplicationBuilder {
  House build( const std::string & house_name) {
    return new House( house_name,
                      new Kitchen(new Sink(),
                                  new Dishwasher(),
                                  new Refrigerator())
                    );
  }
}

Nota che la mia chiamata al metodo Factory è cambiata da questo:

ApplicationBuilder builder;
House * my_house = builder.build();

A questo:

ApplicationBuilder builder;
House * my_house = builder.build("Michaels-Treehouse");

A proposito: penso che il concetto di separazione delle istanze dell'oggetto dalla logica aziendale sia eccezionale, sto solo cercando di capire come posso applicarlo alla mia situazione. Ciò che mi confonde è che tutti gli esempi che ho visto del modello Factory non passano mai alcun parametro nella funzione build ().

Per essere chiari: non conosco il nome della casa fino al momento prima che devo istanziarlo.

È stato utile?

Soluzione

Ho visto molti esempi che usano una serie fissa di argomenti, come nel tuo esempio di nome, e li ho usati anche io e non riesco a vedere nulla di sbagliato in esso.

Tuttavia c'è una buona ragione per cui molti tutorial o piccoli articoli evitano di mostrare fabbriche che inoltrano parametri agli oggetti costruiti: praticamente è impossibile inoltrare un numero arbitrario di argomenti (anche per un limite sano come 6 argomenti). Ogni parametro che inoltri deve essere accettato come const T& e T& se vuoi farlo generico.

Per esempi più complicati, tuttavia, è necessario un insieme di sovraccarichi in modo esponenziale (per ogni parametro, una versione const e una nonconst) e perfetto inoltro non è affatto possibile (quindi i temporali vengono inoltrati come provvisori, per esempio). Per il prossimo standard C ++ il problema è stato risolto:

class ApplicationBuilder {
  template<typename... T>
  House *build( T&&... t ) {
    return new House( std::forward<T>(t)...,
                      new Kitchen(new Sink(),
                                  new Dishwasher(),
                                  new Refrigerator())
                    );
  }
};

In questo modo, puoi chiamare

builder.build("Hello", 13);

E tornerà

new House("Hello", 13, new Kitchen(new Sink(...

Leggi l'articolo che ho linkato sopra.

Altri suggerimenti

Non riesco a capire perché sarebbe sbagliato aggiungere questo parametro alla tua fabbrica. Ma tieni presente che non dovresti finire per aggiungere molti parametri che potrebbero non essere utili a tutti gli oggetti creati dalla fabbrica. Se lo fai, avrai perso molti dei vantaggi di una fabbrica!

Non solo è accettabile, ma è comune passare i parametri a un metodo di fabbrica. Dai un'occhiata a alcuni esempi . Normalmente il parametro è un tipo che dice alla fabbrica cosa fare, ma non c'è motivo per cui non è possibile aggiungere altre informazioni necessarie per costruire un oggetto. Penso che quello che stai facendo vada bene.

L'idea di una factory è che ti dà un'istanza di una classe / interfaccia, quindi non c'è nulla di sbagliato nel passaggio dei parametri. Se ci fosse, sarebbe male passare anche i parametri a un nuovo ().

Sono d'accordo con Benoit. Pensa a una fabbrica per creare qualcosa come connessioni sql, in un caso come questo sarebbe necessario passare informazioni sulla connessione alla fabbrica. La fabbrica utilizzerà tali informazioni per utilizzare il protocollo server corretto e così via.

Certo, perché no ..!?

La cosa bella del passaggio dei parametri è che ti permette di nascondere l'implementazione dell'oggetto concreto. Ad esempio, nel codice che hai pubblicato passi i parametri al costruttore. Tuttavia, è possibile modificare l'implementazione in modo che vengano superate tramite un metodo Initiailze . Passando i parametri al metodo factory nascondi la natura della costruzione e dell'inizializzazione dell'oggetto dal chiamante.

Dai un'occhiata a Loki :: Factory, c'è comunque un'implementazione molto simile a quella di Boost. Alcuni esempi di codice che uso regolarmente in diversi gusti:

typedef Loki :: SingletonHolder < Loki :: Fabbrica lt &; Component, std :: string, Loki :: Typelist & Lt; const DataCollection & amp ;, Loki :: Typelist < Gioco *, Loki :: NullType & Gt; gt &; gt &; gt &; ComponentFactory;

Questo potrebbe sembrare un po 'strano a prima vista, tuttavia lasciami spiegare questa bestia e quanto sia davvero potente. Fondamentalmente creiamo un singleton che contiene una factory, la maggior parte dei parametri sono per il singleton, Component è il nostro prodotto, std :: string è il nostro tipo di ID di creazione, dopo questo segue un elenco di tipi dei parametri richiesti per la creazione di Componenti (questo può essere definito usando anche una macro per una sintassi meno dettagliata). Dopo questa riga si può semplicemente fare:

ComponentFactory :: Instance (). CreateObject (" someStringAssociatedWithConcreteType " ;, anDataCollection, aGamePointer);

Per creare oggetti, per registrarne uno basta usare ComponentFactory :: Instance (). Register () ;. C'è un grande capitolo sui dettagli nel libro Modern C ++ Design.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top