Quali sono gli svantaggi di una "fabbrica semplice"?

3

Sto leggendo il libro » Head First Design Patterns « di O'Reilly. Prima di spiegare il modello di metodo di fabbrica, introducono prima una fabbrica semplice.

Stanno usando l'esempio di una pizzeria. In un primo passaggio mostrano il problema:

Pizza orderPizza(string type) {
  Pizza pizza;
  if (type.equals("Pepperoni") { pizza = new PepperoniPizza(); }
  else if (type.equals("Salmon") { pizza = new SalmonPizza(); }
  // ... and so on

  pizza.Prepare();
  pizza.Bake();
  pizza.Cut();
  pizza.Pack();
  return pizza;
}

Il problema ovvio è che devi cambiare Pizzeria ogni volta che aggiungi o rimuovi una pizza.
Quindi introducono prima un "Simple Factory Idiom". Sposta la parte di creazione in una classe "SimplePizzaFactory". Ora non devi più modificare Pizzeria quando aggiungi o rimuovi una pizza.

Quindi dicono che questo approccio non è buono, quando hai più di una pizzeria (in diverse città).
Non capisco davvero il loro ragionamento. Forniscono il seguente codice di esempio e quindi dicono che ogni pizzeria non sta utilizzando la procedura come implementata in precedenza ma utilizzava metodi diversi per "cuocere", "tagliare" e "impacchettare" la pizza.

BerlinPizzaFactory berlinFactory = new BerlinPizzaFactory();
Pizzeria berlinPizzeria = new Pizzeria(berlinFactory);
berlinPizza.Order("Pepperoni");

Invece di usare la Fabbrica semplice, suggeriscono di utilizzare il modello di metodo di fabbrica.

Per prima cosa, non vedo perché la BerlinPizzeria dovrebbe non usare la procedura. È sempre una pizzeria e quando chiami Order, stai utilizzando la stessa procedura.

La mia ipotesi migliore è che stanno insinuando che sei in grado di implementare, diciamo, una caffetteria (sto deliberatamente usando qualcosa di completamente diverso per esprimere il mio punto di vista) e utilizzare la fabbrica (dato che è indipendente dalla pizzeria) e prepara la pizza nel modo che preferisci.

Ma anche quando si utilizza il modello di metodo di fabbrica, nessuno ti obbliga a utilizzare la procedura predefinita. È ancora più semplice "nascondere" che lo stai facendo in modo diverso. I loro esempi di codice sono forniti in Java e i metodi Java sono virtuali per impostazione predefinita. Quindi sarei in grado di implementare BerlinPizzeria e sovrascrivere l'ordine (o dover dichiarare esplicitamente il metodo come finale). Il cliente, tuttavia, non si accorgerebbe che la mia BerlinPizzeria sta facendo le cose in modo diverso.

In conclusione, non vedo alcuna differenza significativa tra una fabbrica semplice e il modello di metodo di fabbrica. L'unico vantaggio del modello di metodo di fabbrica che sto vedendo è che si salverebbero alcune classi (vale a dire le fabbriche "in outsourcing").

Quindi, quali sono realmente gli svantaggi di una Simple Factory e perché non è una buona idea quella di "esternalizzare" la parte creatrice?
O qual è davvero il vantaggio del pattern Metodo di fabbrica e perché è una buona idea forzare la parte di creazione che viene implementata nella sottoclasse?

    
posta Em1 31.08.2014 - 10:01
fonte

2 risposte

3

Diamo un'occhiata a Simple Factory L'intenzione per Simple Factory è semplice: produce istanze di classi concrete. Seguendo il tuo esempio: hai un Pizzeria con metodi come order() :

public enum Pizzas {
    QUADDROSTAGGIONI, SALMONE, ROMANA
}

public class Pizzeria {        
    public static Pizza order(Pizzas type){
        switch(type){
            case ROMANA: return new Romana();
            case SALMONE: return new Salmone();
            case QUADDROSTAGGIONI: return new Quaddrostaggioni();
            default: throw new NoRecipeException();
        }
    }

}

Questo è davvero un caso semplice di fabbrica. Se decidi che vuoi un Salmone -Pizza, devi semplicemente ordinare un'istanza come questa:

  Pizza salmone=Pizzeria.order(Pizzas.SALMONE);

Il vantaggio : hai separato l'uso di Pizzas dalla sua creazione. Vuoi solo Pizza, indipendentemente dal suo processo di creazione. Si può gustare la pizza senza cuocere da soli.

Lo svantaggio : se hai diversi sottotipi di gusti specifici di Pizza (ad es. ROMANABerlinStyle, ROMANAHamburgStyle) hai due scelte.

1) per aggiungere il nuovo tipo alla Pizzeria esistente. Ciò ingombra la tua Pizzeria e devi affrontare diversi gusti, che non sono poi così diversi (ad esempio, ROMANABerlinStyle aggiunge aglio e ROMANAHamburgStyle aggiunge aglio selvatico) in una Pizzeria. Inoltre: non è un vantaggio sapere che si consuma una pizza in stile berlino o hamburg. Volevi solo un tipo di pizza ben definito dalla Pizzeria.

2) tu estrai un ulteriore passo avanti: separi i singoli sapori dei tipi dati QUADDROSTAGGIONI, SALMONE, ROMANA in fabbriche indipendenti. Ciò significa che BerlinPizzeria conosce la sua ricetta e così fa HamburgPizzeria .

Ora puoi avere molte diverse pizzerie che potrebbero avere le loro ricette:

La tradizionale pizzeria dall'alto

public class PizzeriaImpl implements Pizzeria {

    public Pizza order(Pizzas type){
        switch(type){
            case ROMANA: return new Romana();
            case SALMONE: return new Salmone();
            case QUADDROSTAGGIONI: return new Quaddrostaggioni();
            default: throw new NoRecipeException();
        }
    }

}

e uno in stile berlino

public class BerlinPizzeriaImpl implements Pizzeria{

    public Pizza order(Pizzas type){
        switch(type){
            case ROMANA: return new BerlinRomana();
            case SALMONE: return new BerlinSalmone();
            case QUADDROSTAGGIONI: return new Quaddrostaggioni();
            default: throw new NoRecipeException();
        }
    }

}

Ora sei in grado di iniziare il tuo franchising:

public class PizzaFranchiseImpl implements Pizzeria{

    Pizzeria p;

    public  Pizza order(Pizzas type){
        return p.order(type);
    }

    public PizzaFranchiseImpl(Pizzeria p){
        this.p=p;
    };

}

Se ti trovi a Berlino devi semplicemente iniettare il tuo BerlinPizzeriaImpl .

Il vantaggio : sei libero di decidere quale sapore supportare in ogni città ( BerlinRomana, BerlinSalmone, Quadrostaggioni tradizionali ). E questo è completamente trasparente per il tuo cliente / consumatore.

Questo segue il principio OpenClosed : la tua pizzeria è chiusa, in quanto hai un set fisso di pizze, che consegni ( QUADDROSTAGGIONI, SALMONE, ROMANA ), ma sei aperto a nuovi sapori, ad es berlinstyle .

Inoltre: ogni pizzeria è dedicata a uno stile di pizza. Il BerlinPizzeriaImpl non si cura come fare un Romana tradizionale ( Principio di Responsabilità Univoco ).

Ultimo ma non meno importante, disaccoppia diversi stili di pizza dal franchising. Il franchising deve solo sapere come gestire gli ordini.

EDIT: ho sostituito il cadavere con un pesce delizioso ma morto: D

    
risposta data 31.08.2014 - 11:57
fonte
0

Prima di tutto, ho letto quel libro e lo adoro.

L'implementazione classica di Simple Factory è solo un insieme di metodi "static create" racchiusi in una classe.

Puoi affermare di separare l'implementazione della classe dalla sua creazione, ma il gioco è fatto. Non ci sono ulteriori vantaggi e anche questa affermazione è discutibile. Dal mio punto di vista, stai solo separando alcuni metodi statici di creazione in un file diverso.

Nella maggior parte dei casi reali, si finisce con un enorme "file" che produce non solo pizze, ma anche molti altri oggetti non correlati come Burguers, Icecreams, ... in modo da infrangere il principio di responsabilità singola. Questo perché all'inizio hai solo un paio di metodi di creazione della maggior parte delle cose, quindi la cosa "naturale" è raggrupparli in modo che non si sentano soli in una piccola classe di Simple Factory.

Pertanto, i principali svantaggi sono il disordine. Nella maggior parte dei casi si finisce con file enormi o con molti piccoli file.

Tuttavia, la cosa principale è che la Simple Factory non è un modello di progettazione, è solo una convenzione che può essere utile in alcuni casi (ad esempio, test delle unità). Nella maggior parte dei casi hai solo bisogno di un paio di metodi di creazione che possono essere inclusi nella stessa classe (non hai bisogno di una classe esterna per questo).

Se disponi di molti metodi di creazione per una singola classe, hai un grosso problema: o questa classe sta facendo troppo, pensi che passare i parametri sia una cosa negativa o qualsiasi altra ragione casuale.

Il metodo Factory, a differenza di Simple Factory, utilizza l'ereditarietà per risolvere il problema della creazione di oggetti senza specificare le loro classi esatte.

Attendi il capitolo Proxy. Un Proxy (in breve) è un oggetto che "rappresenta" un altro. In questo caso, il metodo Factory può essere utile perché crei un'istanza che può essere il Proxy o l'oggetto reale stesso.

    
risposta data 02.09.2014 - 14:13
fonte

Leggi altre domande sui tag