Quali sono le differenze tra i modelli di design Abstract Factory e Factory?


455

So che ci sono molti post sulle differenze tra questi due schemi, ma ci sono alcune cose che non riesco a trovare.

Da quello che ho letto, vedo che il modello del metodo factory consente di definire come creare un singolo prodotto concreto, ma nascondendo l'implementazione dal client quando vedranno un prodotto generico. La mia prima domanda riguarda la fabbrica astratta. Il suo ruolo è quello di permetterti di creare famiglie di oggetti concreti (che possono dipendere da quale specifica fabbrica usi) piuttosto che un singolo oggetto concreto? La fabbrica astratta restituisce solo un oggetto molto grande o molti oggetti a seconda dei metodi che chiami?

Le mie ultime due domande riguardano una singola citazione che non riesco a comprendere appieno di aver visto in numerosi luoghi:

Una differenza tra i due è che con il modello Fabbrica astratta, una classe delega la responsabilità dell'istanza dell'oggetto a un altro oggetto tramite la composizione, mentre il modello Metodo di fabbrica utilizza l'ereditarietà e si basa su una sottoclasse per gestire l'istanza dell'oggetto desiderata.

La mia comprensione è che il modello di metodo di fabbrica ha un'interfaccia Creator che renderà ConcreteCreator responsabile di sapere quale ConcreteProduct istanziare. È questo che significa usare l'ereditarietà per gestire l'istanza di oggetti?

Ora, per quanto riguarda quella citazione, come fa esattamente il modello di Fabbrica Astratta a delegare la responsabilità dell'istanza dell'oggetto a un altro oggetto tramite la composizione? Cosa significa questo? Sembra che anche il modello Abstract Factory usi l'eredità per fare il processo di costruzione anche ai miei occhi, ma poi sto ancora imparando su questi modelli.

Qualsiasi aiuto, specialmente con l'ultima domanda, sarebbe molto apprezzato.



Vedere "come l'istanza creata" dal punto di vista del cliente ti aiuterebbe a capire il preventivo.
Karthik Bose,

@nawfal, le risposte in quel thread sono orribili.
jaco0646,

Risposte:


494

La differenza tra i due

La differenza principale tra un "metodo di fabbrica" ​​e una "fabbrica astratta" è che il metodo di fabbrica è un metodo singolo e una fabbrica astratta è un oggetto. Penso che molte persone confondano questi due termini e iniziano a usarli in modo intercambiabile. Ricordo che ho avuto difficoltà a trovare esattamente quale fosse la differenza quando li ho imparati.

Poiché il metodo factory è solo un metodo, può essere sostituito in una sottoclasse, quindi nella seconda metà del tuo preventivo:

... il modello Metodo di fabbrica utilizza l'ereditarietà e si basa su una sottoclasse per gestire l'istanza dell'oggetto desiderata.

La citazione presuppone che un oggetto chiami qui il proprio metodo factory. Pertanto, l'unica cosa che potrebbe modificare il valore restituito sarebbe una sottoclasse.

La fabbrica astratta è un oggetto che ha più metodi di fabbrica. Guardando la prima metà del tuo preventivo:

... con il modello Fabbrica astratta, una classe delega la responsabilità dell'istanza dell'oggetto a un altro oggetto tramite la composizione ...

Quello che stanno dicendo è che esiste un oggetto A, che vuole creare un oggetto Foo. Invece di creare l'oggetto Foo stesso (ad es. Con un metodo factory), otterrà un oggetto diverso (la fabbrica astratta) per creare l'oggetto Foo.

Esempi di codice

Per mostrarti la differenza, ecco un metodo di fabbrica in uso:

class A {
    public void doSomething() {
        Foo f = makeFoo();
        f.whatever();   
    }

    protected Foo makeFoo() {
        return new RegularFoo();
    }
}

class B extends A {
    protected Foo makeFoo() {
        //subclass is overriding the factory method 
        //to return something different
        return new SpecialFoo();
    }
}

Ed ecco una fabbrica astratta in uso:

class A {
    private Factory factory;

    public A(Factory factory) {
        this.factory = factory;
    }

    public void doSomething() {
        //The concrete class of "f" depends on the concrete class
        //of the factory passed into the constructor. If you provide a
        //different factory, you get a different Foo object.
        Foo f = factory.makeFoo();
        f.whatever();
    }
}

interface Factory {
    Foo makeFoo();
    Bar makeBar();
    Aycufcn makeAmbiguousYetCommonlyUsedFakeClassName();
}

//need to make concrete factories that implement the "Factory" interface here

15
Questa è una grande spiegazione. Ma qual è la parte più importante che rimane senza risposta, e cioè: quando usarne una e quando l'altra?
croraf,

11
Non sono sicuro che sia corretto. Abbastanza sicuro Factory Method è un modello di progettazione che prende il nome dai metodi factory, ma implica la struttura e l'ereditarietà delle classi. Non è un singolo metodo.
Aviv Cohn,

2
Quindi è corretto dire: il metodo Factory può essere un metodo in tutte le classi regolari con scopi diversi. Ma la Fabbrica astratta è una classe / oggetto utilizzato da un cliente ed è SOLO responsabile della creazione di alcuni prodotti in una famiglia?
Hieu Nguyen,

Stai usando la parola "Super" in "SuperFoo" solo per indicare un caso speciale di Foo, o in realtà significa super classe? Come immaginavo, doveva essere una sottoclasse.
Dahui,

@dahui Sì, è una sottoclasse. L'ho modificato SpecialFooper essere più chiaro.
Tom Dalling,

125

La fabbrica astratta crea una classe base con metodi astratti che definiscono i metodi per gli oggetti che dovrebbero essere creati. Ogni classe di fabbrica che deriva la classe di base può creare la propria implementazione di ciascun tipo di oggetto.

inserisci qui la descrizione dell'immagine

Il metodo factory è solo un metodo semplice utilizzato per creare oggetti in una classe. Di solito viene aggiunto nella radice aggregata (la Orderclasse ha un metodo chiamato CreateOrderLine)

inserisci qui la descrizione dell'immagine

Fabbrica astratta

Nell'esempio che segue progettiamo un'interfaccia in modo da poter separare la creazione della coda da un sistema di messaggistica e quindi creare implementazioni per diversi sistemi di coda senza dover cambiare la base di codice.

interface IMessageQueueFactory
{
  IMessageQueue CreateOutboundQueue(string name);
  IMessageQueue CreateReplyQueue(string name);
}

public class AzureServiceBusQueueFactory : IMessageQueueFactory
{
      IMessageQueue CreateOutboundQueue(string name)
      {
           //init queue
           return new AzureMessageQueue(/*....*/);
      }

      IMessageQueue CreateReplyQueue(string name)
      {
           //init response queue
           return new AzureResponseMessageQueue(/*....*/);
      }

}

public class MsmqFactory : IMessageQueueFactory
{
      IMessageQueue CreateOutboundQueue(string name)
      {
           //init queue
           return new MsmqMessageQueue(/*....*/);
      }

      IMessageQueue CreateReplyQueue(string name)
      {
           //init response queue
           return new MsmqResponseMessageQueue(/*....*/);
      }
}

Metodo di fabbrica

Il problema nei server HTTP è che abbiamo sempre bisogno di una risposta per ogni richiesta.

public interface IHttpRequest
{
    // .. all other methods ..

    IHttpResponse CreateResponse(int httpStatusCode);
}

Senza il metodo factory, gli utenti del server HTTP (ovvero i programmatori) sarebbero costretti a utilizzare classi specifiche di implementazione che vanificano lo scopo IHttpRequestdell'interfaccia.

Pertanto introduciamo il metodo factory in modo che anche la creazione della classe di risposta venga sottratta.

Sommario

La differenza è che lo scopo previsto della classe contenente un metodo factory non è quello di creare oggetti , mentre una factory astratta dovrebbe essere utilizzata solo per creare oggetti.

Bisogna fare attenzione quando si usano i metodi di fabbrica poiché è facile rompere l'LSP ( principio di sostituzione di Liskov ) quando si creano oggetti.


3
Perché abbiamo bisogno di un prodotto concreto?
Andrew S,

60
Perché nessuno vuole investire in idee.
Jgauffin,

4
The Abstract Factory dovrebbe creare qualcosa di più che Button()creare una "famiglia di prodotti correlati". Ad esempio, l'esempio canonico GoF crea ScrollBar()e Window(). Il vantaggio è che la Fabbrica astratta può applicare un tema comune ai suoi molteplici prodotti.
jaco0646,

Jaco ha ragione. Considera che entrambi i diagrammi UML sono essenzialmente gli stessi (a parte UML di Abstract Factory che è sbagliato). In entrambi i casi il client chiama un metodo factory per la creazione di un singolo prodotto.
cobby

1
@AndrewS: per rispondere alla tua domanda. Se non abbiamo bisogno di avere prodotti concreti (classi) diversi per la stessa astrazione (interfaccia), probabilmente abbiamo bisogno del modello del costruttore e non del modello di fabbrica. (meglio tardi che mai;))
jgauffin

95

Le differenze tra i modelli di design AbstractFactory e Factory sono le seguenti:

  • Il metodo Factory viene utilizzato per creare un solo prodotto, ma Abstract Factory riguarda la creazione di famiglie di prodotti correlati o dipendenti.
  • Il modello Metodo di fabbrica espone un metodo al client per la creazione dell'oggetto mentre nel caso di Fabbrica astratta espongono una famiglia di oggetti correlati che possono consistere in questi metodi di Fabbrica.
  • Il modello Metodo di fabbrica nasconde la costruzione di un singolo oggetto, mentre Fabbrica astratta nasconde la costruzione di una famiglia di oggetti correlati. Le fabbriche astratte sono di solito implementate usando (un insieme di) metodi di fabbrica.
  • Il modello Factory astratto utilizza la composizione per delegare la responsabilità di creare un oggetto in un'altra classe mentre il modello di progettazione Metodo di fabbrica utilizza l'ereditarietà e si basa su una classe o sottoclasse derivata per creare un oggetto.
  • L'idea alla base del modello Metodo di fabbrica è che consente il caso in cui un client non sa quali classi concrete sarà necessario creare in fase di esecuzione, ma vuole solo ottenere una classe che farà il lavoro mentre il modello Abstract Factory è meglio utilizzato quando il sistema deve creare più famiglie di prodotti o si desidera fornire una libreria di prodotti senza esporre i dettagli di implementazione.!

Implementazione del modello del metodo di fabbrica: Metodo di fabbrica UML

Implementazione astratta del modello di fabbrica:

Fabbrica astratta UML


13
Mmm, non sono sicuro dell'esempio di fabbrica astratta. Penso che la fabbrica delle forme e la fabbrica dei colori dovrebbero implementare gli stessi metodi. Ma se ho ragione, allora il campione non ha senso.
Joaquin Iurchuk,

4
I punti elenco sono corretti; tuttavia, entrambi i diagrammi sono completamente sbagliati e molto fuorvianti. Vedi il diagramma seguente da @ Trying per un modello accurato di Abstract Factory.
jaco0646,

1
devo ammettere che i 2 diagrammi sono davvero molto fuorvianti. Li ho visti nel sito Web tutorialspoint e ad essere onesti non sono d'accordo al 100% con loro. Le descrizioni sembrano buone però
SoftwareDeveloper

Questo è molto fuorviante.
Diyoda_

50+ voti e i diagrammi sono molto sbagliati. Prova che non puoi fidarti di molte risposte di pattern di progettazione su SO.
Fuhrmanator,

27

La differenza principale tra Abstract Factory e Factory Method è che Abstract Factory è implementato da Composition ; ma il metodo Factory è implementato da Inheritance .

Sì, hai letto bene: la differenza principale tra questi due schemi è la vecchia composizione rispetto all'eredità dibattito tra .

I diagrammi UML sono disponibili nel libro (GoF). Voglio fornire esempi di codice, perché penso che combinare gli esempi delle prime due risposte in questo thread fornirà una dimostrazione migliore di entrambe le risposte da sole. Inoltre, ho usato la terminologia del libro nei nomi di classe e metodo.

Fabbrica astratta

  1. Il punto più importante da capire qui è che viene iniettata la fabbrica astratta nel client. Questo è il motivo per cui diciamo che Abstract Factory è implementato da Composition. Spesso, un framework di iniezione di dipendenza eseguiva tale compito; ma un framework non è richiesto per DI.
  2. Il secondo punto critico è che le fabbriche concrete qui non lo sono implementazioni con il metodo Factory! Di seguito è riportato un esempio di codice per il metodo di fabbrica.
  3. E infine, il terzo punto da notare è la relazione tra i prodotti: in questo caso le code in uscita e di risposta. Una fabbrica concreta produce code di Azure, l'altra MSMQ. Il GoF si riferisce a questa relazione di prodotto come a una "famiglia" ed è importante essere consapevoli che la famiglia in questo caso non significa gerarchia di classi.
public class Client {
    private final AbstractFactory_MessageQueue factory;

    public Client(AbstractFactory_MessageQueue factory) {
        // The factory creates message queues either for Azure or MSMQ.
        // The client does not know which technology is used.
        this.factory = factory;
    }

    public void sendMessage() {
        //The client doesn't know whether the OutboundQueue is Azure or MSMQ.
        OutboundQueue out = factory.createProductA();
        out.sendMessage("Hello Abstract Factory!");
    }

    public String receiveMessage() {
        //The client doesn't know whether the ReplyQueue is Azure or MSMQ.
        ReplyQueue in = factory.createProductB();
        return in.receiveMessage();
    }
}

public interface AbstractFactory_MessageQueue {
    OutboundQueue createProductA();
    ReplyQueue createProductB();
}

public class ConcreteFactory_Azure implements AbstractFactory_MessageQueue {
    @Override
    public OutboundQueue createProductA() {
        return new AzureMessageQueue();
    }

    @Override
    public ReplyQueue createProductB() {
        return new AzureResponseMessageQueue();
    }
}

public class ConcreteFactory_Msmq implements AbstractFactory_MessageQueue {
    @Override
    public OutboundQueue createProductA() {
        return new MsmqMessageQueue();
    }

    @Override
    public ReplyQueue createProductB() {
        return new MsmqResponseMessageQueue();
    }
}

Metodo di fabbrica

  1. Il punto più importante da comprendere qui è che ConcreteCreator è il client. In altre parole, il client è una sottoclasse il cui genitore definisce il factoryMethod(). Questo è il motivo per cui diciamo che il metodo Factory è implementato da Inheritance.
  2. Il secondo punto critico è ricordare che il modello di metodo di fabbrica non è altro che una specializzazione del modello di modello di modello. I due modelli condividono una struttura identica. Differiscono solo nello scopo. Il Metodo Factory è creazionale (costruisce qualcosa) mentre il Metodo Template è comportamentale (calcola qualcosa).
  3. E infine, il terzo punto da notare è che la Creatorclasse (parent) invoca la propria factoryMethod(). Se rimuoviamo anOperation()dalla classe genitore, lasciando solo un solo metodo, non è più il modello Metodo di fabbrica. In altre parole, il metodo Factory non può essere implementato con meno di due metodi nella classe genitore; e uno deve invocare l'altro.
public abstract class Creator {
    public void anOperation() {
        Product p = factoryMethod();
        p.whatever();
    }

    protected abstract Product factoryMethod();
}

public class ConcreteCreator extends Creator {
    @Override
    protected Product factoryMethod() {
        return new ConcreteProduct();
    }
}

Varie. E modelli di fabbrica vari

Tieni presente che sebbene il GoF definisca due diversi modelli Factory, questi non sono gli unici modelli Factory esistenti. Non sono nemmeno necessariamente i modelli Factory più comunemente usati. Un terzo esempio famoso è lo Static Factory Pattern di Josh Bloch di Effective Java. Il libro Head First Design Patterns include ancora un altro modello che chiamano Simple Factory.

Non cadere nella trappola di supporre che ogni modello Factory debba corrispondere a uno dal GoF.


3
Risposta eccellente e molto chiara basata su buoni esempi, il migliore in questo argomento IMO.
Luke Duda,

Ottima spiegazione +1 per il metodo Factory deve invocare il punto del metodo factory astratto. Con questo punto è molto chiaro, senza capire questo punto: se abbiamo il metodo factory che non viene invocato da se stesso implica che sarà usato da qualche altra classe che lo comporrà e le sue sottoclassi verranno iniettate, si trasformerà in fabbrica astratta , la differenza diventa meno chiara se si
ritiene

Un'altra osservazione-domanda. Dovrebbe factoryMethod()essere sempre il protected metodo nel modello "Metodo di fabbrica"? (Penso di si)
Yaroslav Fedoruk,

1
@YaroslavFedoruk, il libro GoF consente i publicmetodi di fabbrica e il metodo non deve nemmeno essere abstract; ma il punto critico è che il metodo è destinato all'eredità, quindi non può (per esempio) essere statico final. Ho realizzato il metodo protectede abstractqui per evidenziare l'estensibilità (obbligatoria).
jaco0646,

@ nits.kk, potresti essere interessato a una risposta correlata .
jaco0646,

26

Abstract Factory è un'interfaccia per la creazione di prodotti correlati, ma Factory Method è solo un metodo. Abstract Factory può essere implementato con più metodi Factory.

Fabbrica astratta UML


10
Hai già pubblicato la stessa risposta qui . Se ritieni che questa domanda sia simile, contrassegnala invece come duplicata.
Ja͢ck,

11

Considera questo esempio per una facile comprensione.

Cosa forniscono le società di telecomunicazioni? Banda larga, linea telefonica e cellulare per esempio e ti viene chiesto di creare un'applicazione per offrire i loro prodotti ai loro clienti.

Generalmente, ciò che faresti qui è creare prodotti, ad esempio banda larga, linea telefonica e cellulare tramite il tuo metodo di fabbrica dove sai quali proprietà hai per quei prodotti ed è piuttosto semplice.

Ora, la società vuole offrire ai propri clienti un pacchetto di prodotti, ovvero banda larga, linea telefonica e dispositivi mobili, e qui arriva la Fabbrica astratta .

Abstract Factory è, in altre parole, la composizione di altre fabbriche che sono responsabili della creazione dei propri prodotti e Abstract Factory sa come collocare questi prodotti in modo più significativo nel rispetto delle proprie responsabilità.

In questo caso, the BundleFactoryis the Abstract Factory BroadbandFactory, PhonelineFactorye MobileFactorysono i Factory. Per semplificare di più, queste fabbriche avranno il metodo di fabbrica per inizializzare i singoli prodotti.

Vedi l'esempio di codice qui sotto:

public class BroadbandFactory : IFactory {
    public static Broadband CreateStandardInstance() {
        // broadband product creation logic goes here
    }
}

public class PhonelineFactory : IFactory {
    public static Phoneline CreateStandardInstance() {
        // phoneline product creation logic goes here
    }
}

public class MobileFactory : IFactory {
    public static Mobile CreateStandardInstance() {
        // mobile product creation logic goes here
    }
}

public class BundleFactory : IAbstractFactory {

    public static Bundle CreateBundle() {
        broadband = BroadbandFactory.CreateStandardInstance();
        phoneline = PhonelineFactory.CreateStandardInstance();
        mobile = MobileFactory.CreateStandardInstance();

        applySomeDiscountOrWhatever(broadband, phoneline, mobile);
    }

    private static void applySomeDiscountOrWhatever(Broadband bb, Phoneline pl, Mobile m) {
        // some logic here
        // maybe manange some variables and invoke some other methods/services/etc.
    }
}

Spero che sia di aiuto.


1
Non esistono staticmetodi in nessuno dei pattern di fabbrica GoF. Questo è sbagliato.
jaco0646,

5

Esempio di vita reale. (Facile da ricordare)

Fabbrica

Immagina di costruire una casa e ti avvicini a un falegname per una porta. Dai la misura per la porta e le tue esigenze e lui costruirà una porta per te. In questo caso, il falegname è una fabbrica di porte. Le vostre specifiche sono ingressi per la fabbrica e la porta è l'uscita o il prodotto dalla fabbrica.

Fabbrica astratta

Ora, considera lo stesso esempio di porta. Puoi andare da un falegname o puoi andare in un negozio di porte di plastica o in un negozio di PVC. Tutti sono fabbriche di porte. In base alla situazione, decidi a quale tipo di fabbrica devi avvicinarti. Questo è come una fabbrica astratta.

Ho spiegato qui sia il modello del metodo Factory sia il modello astratto della fabbrica a partire dal non usarli spiegando i problemi e quindi risolvendo i problemi utilizzando i modelli sopra https://github.com/vikramnagineni/Design-Patterns/tree/master


3

Mettiamo in chiaro che la maggior parte delle volte nel codice di produzione, utilizziamo un modello di fabbrica astratto perché la classe A è programmata con l'interfaccia B. E A deve creare istanze di B. Quindi A deve avere un oggetto factory per produrre istanze di B Quindi A non dipende da nessuna istanza concreta di B. Spero che sia d'aiuto.


3

Comprendi le differenze nelle motivazioni:

Supponiamo che tu stia costruendo uno strumento in cui hai oggetti e un'implementazione concreta delle interrelazioni degli oggetti. Dato che prevedi variazioni negli oggetti, hai creato una direzione indiretta assegnando la responsabilità di creare varianti degli oggetti a un altro oggetto ( lo chiamiamo fabbrica astratta ). Questa astrazione trova un grande vantaggio poiché prevedi future estensioni che richiedono varianti di quegli oggetti.

Un'altra motivazione piuttosto intrigante in questa linea di pensiero è un caso in cui tutti gli oggetti di tutto il gruppo avranno una variante corrispondente. In base ad alcune condizioni, verrà utilizzata una delle varianti e in ogni caso tutti gli oggetti devono essere della stessa variante. Questo potrebbe essere un po 'contro intuitivo da capire, poiché spesso tendiamo a pensare che - purché le varianti di un oggetto seguano un contratto uniforme comune ( interfaccia in senso lato ), il codice di implementazione concreto non dovrebbe mai infrangersi. Il fatto interessante qui è che, non sempre questo è vero soprattutto quando il comportamento previsto non può essere modellato da un contratto di programmazione.

Un semplice ( prendendo in prestito l'idea da GoF ) è che qualsiasi applicazione GUI dice un monitor virtuale che emula l'aspetto di MS o Mac o del sistema operativo Fedora. Qui, ad esempio, quando tutti gli oggetti widget come finestra, pulsante, ecc. Hanno una variante MS ad eccezione di una barra di scorrimento derivata dalla variante MAC, lo scopo dello strumento fallisce male.

Questi casi di cui sopra costituiscono il bisogno fondamentale di Abstract Factory Pattern .

D'altra parte, immagina di scrivere un framework in modo che molte persone possano creare vari strumenti ( come quello negli esempi sopra ) usando il tuo framework. Dall'idea stessa di un framework, non è necessario, anche se non è possibile utilizzare oggetti concreti nella propria logica. Preferisci mettere alcuni contratti di alto livello tra vari oggetti e il modo in cui interagiscono. Mentre tu ( come sviluppatore di framework ) rimani a un livello molto astratto, ogni costruttore dello strumento è costretto a seguire i tuoi costrutti di framework. Tuttavia, loro ( i costruttori di strumenti ) hanno la libertà di decidere quale oggetto costruire e come interagiranno tutti gli oggetti che creano. A differenza del caso precedente ( di Abstract Factory Pattern ), tu ( come creatore di framework) in questo caso non è necessario lavorare con oggetti concreti; e piuttosto può rimanere a livello di contratto degli oggetti. Inoltre, a differenza della seconda parte delle motivazioni precedenti, tu o i costruttori di utensili non avete mai le situazioni di mescolare oggetti da varianti. Qui, mentre il codice del framework rimane a livello di contratto, ogni costruttore di strumenti è limitato ( dalla natura del caso stesso ) all'utilizzo dei propri oggetti. Le creazioni di oggetti in questo caso sono delegate a ciascun implementatore e i provider di framework forniscono solo metodi uniformi per la creazione e la restituzione di oggetti. Tali metodi sono inevitabili per lo sviluppatore del framework per procedere con il loro codice e ha un nome speciale chiamato metodo Factory ( Factory Method Pattern per il pattern sottostante ).

Alcune note:

  • Se hai familiarità con il "metodo modello", allora vedresti che i metodi di fabbrica sono spesso invocati dai metodi modello nel caso di programmi appartenenti a qualsiasi forma di framework. Al contrario, i metodi modello di programmi applicativi sono spesso semplici implementazioni di algoritmi specifici e nulla di metodi di fabbrica.
  • Inoltre, per la completezza dei pensieri, usando il framework ( menzionato sopra ), quando un costruttore di strumenti sta costruendo uno strumento, all'interno di ciascun metodo di fabbrica, invece di creare un oggetto concreto, può delegare ulteriormente la responsabilità a un abstract -oggetto di fabbrica, a condizione che il costruttore di strumenti preveda variazioni degli oggetti concreti per future estensioni.

Codice di esempio:

//Part of framework-code
BoardGame {
    Board createBoard() //factory method. Default implementation can be provided as well
    Piece createPiece() //factory method

    startGame(){        //template method
         Board borad = createBoard()
         Piece piece = createPiece()
         initState(board, piece)
    }
}


//Part of Tool-builder code
Ludo inherits  BoardGame {
     Board createBoard(){ //overriding of factory method
         //Option A: return new LudoBoard() //Lodu knows object creation
         //Option B: return LudoFactory.createBoard() //Lodu asks AbstractFacory
     }
….
}

//Part of Tool-builder code
Chess inherits  BoardGame {
    Board createBoard(){ //overriding of factory method
        //return a Chess board
    }
    ….
}

3
  1. La mia prima domanda riguarda la fabbrica astratta. Il suo ruolo è quello di permetterti di creare famiglie di oggetti concreti (che possono dipendere da quale specifica fabbrica usi) piuttosto che un singolo oggetto concreto?

Sì. L'intento di Abstract Factory è:

Fornire un'interfaccia per la creazione di famiglie di oggetti correlati o dipendenti senza specificare le loro classi concrete.


  1. La fabbrica astratta restituisce solo un oggetto molto grande o molti oggetti a seconda dei metodi che chiami?

Idealmente dovrebbe restituire un oggetto per il metodo che il client sta invocando.

  1. La mia comprensione è che il modello di metodo di fabbrica ha un'interfaccia Creator che renderà ConcreteCreator responsabile di sapere quale ConcreteProduct istanziare. È questo che significa usare l'ereditarietà per gestire l'istanza di oggetti?

Sì. Il metodo factory utilizza l'ereditarietà.

  1. Il modello di Fabbrica astratta delega la responsabilità dell'istanza dell'oggetto a un altro oggetto tramite la composizione? Cosa significa questo?

AbstractFactory definisce FactoryMethod e ConcreteFactory è responsabile della costruzione di ConcreteProduct. Segui l'esempio di codice in questo articolo .

Puoi trovare maggiori dettagli nei relativi post SE:

Qual è la differenza di base tra i modelli Factory e Abstract Factory?

Modelli di progettazione: metodo Factory vs Factory vs Factory astratto


3

Il metodo Factory si basa sull'ereditarietà: la creazione di oggetti è delegata a sottoclassi, che implementano il metodo factory per creare oggetti.

Fabbrica astratta si basa sulla composizione degli oggetti: la creazione degli oggetti è implementata nei metodi esposti nell'interfaccia factory.

Schema di alto livello del modello Factory e Abstract factory,

diagramma

Per ulteriori informazioni sul metodo Factory, consultare questo articolo .

Per ulteriori informazioni sul metodo Factory astratto, consultare questo articolo .


2

Per renderlo molto semplice con un'interfaccia minima e focalizzare "// 1":

class FactoryProgram
    {
        static void Main()
        {
            object myType = Program.MyFactory("byte");
            Console.WriteLine(myType.GetType().Name);

            myType = Program.MyFactory("float"); //3
            Console.WriteLine(myType.GetType().Name);

            Console.ReadKey();
        }

        static object MyFactory(string typeName)
        {
            object desiredType = null; //1
            switch (typeName)
            {
                case "byte": desiredType = new System.Byte(); break; //2
                case "long": desiredType = new System.Int64(); break;
                case "float": desiredType = new System.Single(); break;
                default: throw new System.NotImplementedException();
            }
            return desiredType;
        }
    }

Qui i punti importanti: 1. I meccanismi Factory & AbstractFactory devono usare l'ereditarietà (System.Object-> byte, float ...); quindi se hai ereditarietà nel programma, Factory (Abstract Factory non ci sarebbe molto probabilmente) è già lì in base alla progettazione 2. Il Creatore (MyFactory) conosce il tipo di calcestruzzo, quindi restituisce l'oggetto di tipo concreto al chiamante (Principale); In astratto il tipo di ritorno di fabbrica sarebbe un'interfaccia.

interface IVehicle { string VehicleName { get; set; } }
interface IVehicleFactory
    {
        IVehicle CreateSingleVehicle(string vehicleType);
    }
class HondaFactory : IVehicleFactory
    {
        public IVehicle CreateSingleVehicle(string vehicleType)
        {
            switch (vehicleType)
            {
                case "Sports": return new SportsBike();
                case "Regular":return new RegularBike();
                default: throw new ApplicationException(string.Format("Vehicle '{0}' cannot be created", vehicleType));
            }
        }
    }
class HeroFactory : IVehicleFactory
    {
        public IVehicle CreateSingleVehicle(string vehicleType)
        {
            switch (vehicleType)
            {
                case "Sports":  return new SportsBike();
                case "Scooty": return new Scooty();
                case "DarkHorse":return new DarkHorseBike();
                default: throw new ApplicationException(string.Format("Vehicle '{0}' cannot be created", vehicleType));
            }
        }
    }

class RegularBike : IVehicle { public string VehicleName { get { return "Regular Bike- Name"; } set { VehicleName = value; } } }
class SportsBike : IVehicle { public string VehicleName { get { return "Sports Bike- Name"; } set { VehicleName = value; } } }
class RegularScooter : IVehicle { public string VehicleName { get { return "Regular Scooter- Name"; } set { VehicleName = value; } } }
class Scooty : IVehicle { public string VehicleName { get { return "Scooty- Name"; } set { VehicleName = value; } } }
class DarkHorseBike : IVehicle { public string VehicleName { get { return "DarkHorse Bike- Name"; } set { VehicleName = value; } } }

class Program
{
    static void Main(string[] args)
    {
        IVehicleFactory honda = new HondaFactory(); //1
        RegularBike hondaRegularBike = (RegularBike)honda.CreateSingleVehicle("Regular"); //2
        SportsBike hondaSportsBike = (SportsBike)honda.CreateSingleVehicle("Sports");
        Console.WriteLine("******* Honda **********"+hondaRegularBike.VehicleName+ hondaSportsBike.VehicleName);

        IVehicleFactory hero = new HeroFactory();
        DarkHorseBike heroDarkHorseBike = (DarkHorseBike)hero.CreateSingleVehicle("DarkHorse");
        SportsBike heroSportsBike = (SportsBike)hero.CreateSingleVehicle("Sports");
        Scooty heroScooty = (Scooty)hero.CreateSingleVehicle("Scooty");
        Console.WriteLine("******* Hero **********"+heroDarkHorseBike.VehicleName + heroScooty.VehicleName+ heroSportsBike.VehicleName);

        Console.ReadKey();
    }
}

Punti importanti: 1. Requisito: Honda creerebbe "Regular", "Sports" ma Hero creerebbe "DarkHorse", "Sports" e "Scooty". 2. perché due interfacce? Uno per il tipo di produttore (IVehicleFactory) e un altro per la fabbrica del prodotto (IVehicle); un altro modo di comprendere 2 interfacce è la fabbrica astratta consiste nel creare oggetti correlati 2. Il problema è che i figli di IVehicleFactory ritornano e IVehicle (invece del cemento in fabbrica); quindi ottengo la variabile genitore (IVehicle); quindi creo il tipo concreto effettivo chiamando CreateSingleVehicle e quindi eseguendo il casting dell'oggetto padre sull'oggetto figlio reale. Cosa succederebbe se lo facessi RegularBike heroRegularBike = (RegularBike)hero.CreateSingleVehicle("Regular");; otterrai ApplicationException ed è per questo che abbiamo bisogno di una fabbrica astratta generica che spiegherei se necessario.



0

Preferirei la Fabbrica astratta al Metodo di fabbrica in qualsiasi momento. Dall'esempio di Tom Dalling (grande spiegazione tra l'altro), possiamo vedere che la Fabbrica astratta è più compostabile in quanto tutto ciò che dobbiamo fare è passare una Fabbrica diversa al costruttore (iniezione di dipendenza del costruttore in uso qui). Ma il metodo Factory richiede che introduciamo una nuova classe (più cose da gestire) e utilizziamo la sottoclasse. Preferisci sempre la composizione rispetto all'eredità.


0

mi permetta di dirlo con precisione. la maggior parte delle risposte ha già spiegato, fornito anche diagrammi ed esempi. quindi il mio anwer sarebbe solo una fodera. parole mie: - “Il modello astratto di fabbrica aggiunge il livello astratto su più implementazioni di metodi di fabbrica. significa che la fabbrica astratta contiene o compone uno o più di un modello di metodo di fabbrica "


Questo non è corretto Questa è l'idea fin troppo comune che Abstract Factory non sia altro che una fabbrica di fabbriche.
jaco0646,

0

Molte delle risposte di cui sopra non forniscono confronti di codice tra il modello di Fabbrica astratta e Metodo di fabbrica. Di seguito è il mio tentativo di spiegarlo tramite Java. Spero che aiuti qualcuno che ha bisogno di una semplice spiegazione.

Come dice giustamente GoF: Abstract Factory fornisce un'interfaccia per la creazione di famiglie di oggetti correlati o dipendenti senza specificare le loro classi concrete.

        public class Client {
            public static void main(String[] args) {
               ZooFactory zooFactory = new HerbivoreZooFactory();       
               Animal animal1 = zooFactory.animal1();
               Animal animal2 = zooFactory.animal2();
               animal1.sound();
               animal2.sound();

               System.out.println();

               AnimalFactory animalFactory = new CowAnimalFactory();
               Animal animal = animalFactory.createAnimal();
               animal.sound();
            }
        }

        public interface Animal {
            public void sound();
        }

        public class Cow implements Animal {

            @Override
            public void sound() {
                System.out.println("Cow moos");
            }

        }

        public class Deer implements Animal {

            @Override
            public void sound() {
                System.out.println("Deer grunts");
            }

        }

        public class Hyena implements Animal {

            @Override
            public void sound() {
                System.out.println("Hyena.java");
            }

        }

        public class Lion implements Animal {

            @Override
            public void sound() {
                System.out.println("Lion roars");
            }

        }

        public interface ZooFactory {
            Animal animal1();

            Animal animal2();
        }

        public class CarnivoreZooFactory implements ZooFactory {

            @Override
            public Animal animal1() {
                return new Lion();
            }

            @Override
            public Animal animal2() {
                return new Hyena();
            }

        }

        public class HerbivoreZooFactory implements ZooFactory{

            @Override
            public Animal animal1() {
                return new Cow();
            }

            @Override
            public Animal animal2() {
                return new Deer();
            }

        }

        public interface AnimalFactory {
            public Animal createAnimal();
        }

        public class CowAnimalFactory implements AnimalFactory{

            @Override
            public Animal createAnimal() {
                return new Cow();
            }

        }

        public class DeerAnimalFactory implements AnimalFactory{

            @Override
            public Animal createAnimal() {
                return new Deer();
            }

        }

        public class HyenaAnimalFactory implements AnimalFactory{

            @Override
            public Animal createAnimal() {
                return new Hyena();
            }

        }

        public class LionAnimalFactory implements AnimalFactory{

            @Override
            public Animal createAnimal() {
                return new Lion();
            }

        }

Questo non è corretto Questo codice implementa il malinteso fin troppo comune secondo cui la Fabbrica astratta non è altro che una fabbrica di fabbriche.
jaco0646,

1
@ jaco0646 Credo che nel modello di metodo di fabbrica, l'obiettivo sia quello di ottenere un solo prodotto concreto dalla FactoryImpl. Considerando che nel modello di fabbrica astratto, gli FactoryImpl sono responsabili della fornitura di più prodotti simili / correlati in calcestruzzo, per i quali l'interfaccia di Factory prevede un contratto. Quindi ZooFactory non è affatto una fabbrica di fabbriche, come dici tu, ma solo un'interfaccia i cui Impls forniscono prodotti concreti collegati tra loro. Sentiti libero di correggere la mia comprensione se non sei d'accordo.
Jatin Shashoo,

In Metodo di fabbrica, l'attenzione è focalizzata sull'ereditarietà tramite la sottoclassificazione, poiché il Metodo di fabbrica è una specializzazione del modello Metodo modello. La risposta più votata sopra mostra un esempio di codice decente.
jaco0646,

@ jaco0646 1. Significa che nell'esempio sopra, invece di usare le interfacce per AnimalFactory e fornire le sue implementazioni, avrei dovuto usare una classe e sovrascrivere il metodo createAnimal () nelle sue sottoclassi: CowAnimalFactory, LionAnimalFactory, ecc. ?? 2. Inoltre, quali sono i tuoi pensieri sull'esempio mostrato per ZooFactory ??
Jatin Shashoo,

Alla prima domanda: si. Al secondo, ho aggiunto la mia risposta a questa discussione piuttosto che continuare a criticare ogni singola risposta.
jaco0646,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.