Torna indietro   Hardware Upgrade Forum > Software > Programmazione

Recensione Samsung Galaxy Z Fold7: un grande salto generazionale
Recensione Samsung Galaxy Z Fold7: un grande salto generazionale
Abbiamo provato per molti giorni il nuovo Z Fold7 di Samsung, un prodotto davvero interessante e costruito nei minimi dettagli. Rispetto al predecessore, cambiano parecchie cose, facendo un salto generazionale importante. Sarà lui il pieghevole di riferimento? Ecco la nostra recensione completa.
The Edge of Fate è Destiny 2.5. E questo è un problema
The Edge of Fate è Destiny 2.5. E questo è un problema
Bungie riesce a costruire una delle campagne più coinvolgenti della serie e introduce cambiamenti profondi al sistema di gioco, tra nuove stat e tier dell’equipaggiamento. Ma con risorse limitate e scelte discutibili, il vero salto evolutivo resta solo un’occasione mancata
Ryzen Threadripper 9980X e 9970X alla prova: AMD Zen 5 al massimo livello
Ryzen Threadripper 9980X e 9970X alla prova: AMD Zen 5 al massimo livello
AMD ha aggiornato l'offerta di CPU HEDT con i Ryzen Threadripper 9000 basati su architettura Zen 5. In questo articolo vediamo come si comportano i modelli con 64 e 32 core 9980X e 9970X. Venduti allo stesso prezzo dei predecessori e compatibili con il medesimo socket, le nuove proposte si candidano a essere ottimi compagni per chi è in cerca di potenza dei calcolo e tante linee PCI Express per workstation grafiche e destinate all'AI.
Tutti gli articoli Tutte le news

Vai al Forum
Rispondi
 
Strumenti
Old 18-12-2008, 12:31   #1
mcaisco
Member
 
Iscritto dal: Jun 2006
Messaggi: 117
[OOP] Factory Method Design Pattern

Salve,

non riesco a capire bene questo semplice (apparentemente) design pattern. Fondamentalmente quello che io ho capito è che si usa per creare un unico punto centralizzato per la creazione di più oggetti simili fra loro, ma che al momento della creazione non si sa bene quale sia necessario creare. Gli esempi si sprecano. Ma un caso di utilizzo stupido e abbastanza chiaro è il seguente.

Voglio poter creare in un'applicazione varie pizze. A runtime però non so quale pizza potrei dover creare (in base a delle ordinazioni per esempio). Quindi l'idea è creare una classe superiore che rappresenti il concetti di "pizza", classe estesa poi da tante "pizze concrete". A questo punto mi serve centralizzare la creazione delle pizze con una "factory". Ma io qui mi perdo...

Come si implementa questa situazione con il Factory Method?

Da molti schemi (uml e non) trovati sul web sembra che gli elementi di questo design pattern applicati a questo preciso esempio dovrebbero essere:
- una classe AbstractFactoryPizza
- tante ConcreteFactoryPizza ciascuna per ogni tipo di pizza che si può creare (FunghiFactoryPizza, SalameFactoyPizza, MargheritaFactoryPizza...). Ognua di queste classe ovviamente estende la classe astratta AbstractFactoryPizza
- una interfaccia che rappresenti una generica pizza, esempio IPizza
- tante classi che implementano la suddetta inferaccia ciascuna per ogni pizza creabile (quindi parallelamente a prima ci sarebbero FunghiPizza, SalamePizza, MargheritaPizza...)

Io arrivo a capire fino a qui. Però non capisco come questi elementi interagiscano. Non capisco per esempio come potrei fare da un ipotetico main() a chiamare la creazione di una precisa pizza. Teoricamente credo che debba passare tramite l'AbstractFactoryPizza e in qualche modo decidere quale delle "factory concrete" chiamare. Poi queste istanzieranno in qualche modo l'opportuna pizza ok... però come faccio ad usare AbstractFactoryPizza? E' astratta!

Che confusione! Aiuto!
mcaisco è offline   Rispondi citando il messaggio o parte di esso
Old 18-12-2008, 12:52   #2
gugoXX
Senior Member
 
L'Avatar di gugoXX
 
Iscritto dal: May 2004
Città: Londra (Torino)
Messaggi: 3692
In un pezzo di codice scriverai
Codice:
AbstractFactoryPizza ThisFactory = new PizzaMargheritaFactory();
e poi tipicamente andrai a richiamare un codice che accetti una AbstractFactoryPizza che crei l'istanza della pizza giusta, e che ci richimai qualcosa di comune a tutti gli abstract factory oppure a tutte le pizze (altrimenti questa similitudine tra pizze non ci starebbe).

P.es.
Codice:
AbstractFactoryPizza ThisFactory = new PizzaMargheritaFactory();
AbstractPizza = ThisFactory.Creaecuoci();

....

public abstract class AbstractFactoryPizza
{
   public AbstractPizza Creaecuoci()
   {
       AbstractPizza thisPizza= GiveMeInstance();
       thisPizza.AggiungiSale();
       thisPizza.Appiattisci();
       thisPizza.Condisci();
       thisPizza.Cuoci();
       return thisPizza;
   }

   // questo e' un nodo chiave, ovvero il produttore della Factory
   //   Ogni implementazione dovra' ritornare l'oggetto del tipo giusto
   //    Grazie all'inheritance e' possibile, vedi dopo
   //   E' il metodo che lega il livello della singola Factory con
   //      Il livello della classe da produrre
   abstract public AbstractPizza GiveMeInstance();
}

publci abstract class AbstractPizza
{
   public void AggiungiSale()
   {
        //Qui scrivo direttamente il codice per aggiungere il sale
        //  su una qualsiasi pizza
        // Dato che su tutte le pizze il sale si aggiunge nello stesso modo
   }

   // Qui invece non scrivo il codice per condire la pizza, dato
   //   che ogni pizza si condisce in modo diverso
   //   con abstract obbligo la singola implementazione di pizza a
   //   scrivere il codice di come verra' condita
   public abstract void Condisci();

}

public class MargheritaFactory:AbstractPizzaFactory
{   
   // Metodo chiave, lega il livello di intheritance dei factory
   //   con quello degli oggetti creati
   public override AbstractPizza GiveMeInstance()
   {
            return new PizzaMargherita();
          // Possibile, una PizzaMargherita e' una AbstractPizza 
   }
}
__________________
Se pensi che il tuo codice sia troppo complesso da capire senza commenti, e' segno che molto probabilmente il tuo codice e' semplicemente mal scritto.
E se pensi di avere bisogno di un nuovo commento, significa che ti manca almeno un test.

Ultima modifica di gugoXX : 18-12-2008 alle 12:57.
gugoXX è offline   Rispondi citando il messaggio o parte di esso
Old 19-12-2008, 11:25   #3
mcaisco
Member
 
Iscritto dal: Jun 2006
Messaggi: 117
Grazie per la risposta molto esaustiva...

Ci ho riflettuto un po' e diciamo che le cose ora mi sono più chiare per certi versi. Ma non riesco a capire bene come un eventuale client (una classe qualunque, un Main per esempio) possa usare questo pattern.

Nel codice che mi hai indicato per esempio, un eventuale client deve direttamente creare un'istanza di una precisa factory. Infatti nel tuo esempio il client chiama appunto:

AbstractFactoryPizza ThisFactory = new PizzaMargheritaFactory();

Pero' il fatto e' che questo pattern per quanto ho capito, deve prevenire situazioni simili in cui il client deve sapere esattamente che cosa creare.
Quindi diciamo che da qualche parte ci deve essere un metodo unico in cui inserire la scelta centralizzata di che tipo di pizza creare in base a qualche parametro. E il client, sapendo solo questo parametro, chiamerà questo metodo ottenendo quindi una generica IPizza oportunamente istanziata su una pizza concreta che pero' il client non sa assolutamente quale sia. Usera' i metodi dell'interfaccia appunto in maniera trasparente.
Il fatto da chiarire è dove mettere questo metodo unico centralizzato che effettua la scelta di quale Factory richiamare demandando a quella la creazione dell'opportuna pizza. Idealmente mi viene da pensare che questo metodo deve stare nell'AbstractFactoryPizza, così il client in ogni caso deve fare riferimento solo a quella. Però quella è una classe astratta e quindi non può essere istanziata... sono di nuovo confuso.
mcaisco è offline   Rispondi citando il messaggio o parte di esso
Old 19-12-2008, 11:40   #4
gugoXX
Senior Member
 
L'Avatar di gugoXX
 
Iscritto dal: May 2004
Città: Londra (Torino)
Messaggi: 3692
Per fare quello che dici si possono usare i metodi statici.
Per purezza di codice io pero' non legherei la decisione di quale factory restituire all'interno della classe astratta delle factory, quanto piu' aggiungerei una classe Helper statica, dotata (almeno) di un unico metodo statico che restituisce la classe factory sulla base di qualche input

Codice:
public static class AbstractFactoryPizzaHelper
{
    public AbstractFactoryPizza GetFactoryPizza(string input)
   {
      switch (input)
      {
         case "Margherita": return new MargheritaFactory(); break;
         case "Napoli": return new NapoliFactory(); break;
         //etc.
      }
   }
}

// Richiamabile con
AbstractFactoryPizza myFactoryPizza = AbstractFactoryPizzaHelper.GetFactoryPizza("Margherita");
AbstractPizza myPizza = myFactoryPizza.CreaECouci();
Come detto questo metodo puo' anche essere contenuto direttamente classe AbstractFactoryPizza, ma non glielo metterei, perche' anche se permesso introduce una circular reference. Una MargheritaFactory deriva da un AbstractFactoryPizza, mentre introducendo quel metodo AbstractFactoryPizza dipende dall'esistenza di una classe MargheritaFactory
Nulla che non si possa fare (a quel punto sono solo nomi, non sono istanze), ma la soluzione con l'Helper mi piace di piu'
__________________
Se pensi che il tuo codice sia troppo complesso da capire senza commenti, e' segno che molto probabilmente il tuo codice e' semplicemente mal scritto.
E se pensi di avere bisogno di un nuovo commento, significa che ti manca almeno un test.

Ultima modifica di gugoXX : 19-12-2008 alle 11:42.
gugoXX è offline   Rispondi citando il messaggio o parte di esso
Old 19-12-2008, 11:41   #5
banryu79
Senior Member
 
L'Avatar di banryu79
 
Iscritto dal: Oct 2007
Città: Padova
Messaggi: 4131
Io ti linko questo thread, magari ti è utile.
__________________

As long as you are basically literate in programming, you should be able to express any logical relationship you understand.
If you don’t understand a logical relationship, you can use the attempt to program it as a means to learn about it.
(Chris Crawford)
banryu79 è offline   Rispondi citando il messaggio o parte di esso
Old 19-12-2008, 12:10   #6
mcaisco
Member
 
Iscritto dal: Jun 2006
Messaggi: 117
Quote:
Per fare quello che dici si possono usare i metodi statici.
Per purezza di codice io pero' non legherei la decisione di quale factory restituire all'interno della classe astratta...
Ecco infatti anche io avevo pensato al metodo statico e ugualmente avevo storto il naso.

Comunque forse avete inteso male il mio post. La modellazione che ho proposto era solo una mia idea partorita da quello che avevo capito di questo pattern. Però se qualcuno di voi pensa che il pattern in questo caso debba essere utilizzato diversamente me lo dica!

Quote:
Io ti linko questo thread, magari ti è utile.
Si mi sembra che in questo thread l'esempio riportato è esattamente come il mio. Però anche lì se notate, la classe User nel metodo use() istanzia direttamente due factory precise (Subclass1Factory() e Subclass2Factory()).
Pero' in generale una classe client come questa non dovrebbe trovarsi nella condizione di sapere esattamente qualche factory chiamare no?! Altrimenti scusate allora avrebbe chiamato direttamente i costruttori delle due classi Subclass1 e Subclass2 no?!

Nel mio esempio quindi un ipotetico client Cameriere prende l'ordinazione e riferisce al DirettoreDellaCucina i nomi delle pizze da creare. Ma non deve sapere esattamente ogni volta quali sono queste pizze. L'ordinazione può essere di 1 pizza come di 100, il cameriere prende nota solo del nome che è come se fosse un ID. Il DirettoreDellaCucina in sostanza dovrebbe essere una sorta di AbstractFactory che poi andrà dal cuoco opportuno (è una pizzeria di lusso!!) e gli dirà di cucinare la pizza per cui lui è specializzato. In questa visione quindi il client è il Cameriere che prende le ordinazioni e deve rivolgersi al DirettoreDellaCucina per ottenere la pizza da consegnare al tavolo. Per rivolgersi al DirettoreDellaCucina però deve usare appunto un metodo unico che dovrebbe essere una sorta di "dammiQuestaPizza(IDpizza)". Ma questo metodo unico dove sta? Teoricamente deve stare in una classe che abbia la visione completa di tutte le factory di pizze esistenti, creando un unico punto centralizzato per la creazione. E a me pare quindi che deve stare dentro DirettoreDellaCucina no?! Pero' si ritorna al discorso del metodo statico...

Sto andando a tentoni eh!?

Ultima modifica di mcaisco : 19-12-2008 alle 12:18.
mcaisco è offline   Rispondi citando il messaggio o parte di esso
Old 19-12-2008, 13:04   #7
banryu79
Senior Member
 
L'Avatar di banryu79
 
Iscritto dal: Oct 2007
Città: Padova
Messaggi: 4131
Quote:
Originariamente inviato da mcaisco Guarda i messaggi
Sto andando a tentoni eh!?
No, va bene: stai ragionando, il che è ottimo, direi.
Aspettiamo di sentire GugoXX o qualcun'altro che ha già usato questo pattern nella pratica.
__________________

As long as you are basically literate in programming, you should be able to express any logical relationship you understand.
If you don’t understand a logical relationship, you can use the attempt to program it as a means to learn about it.
(Chris Crawford)
banryu79 è offline   Rispondi citando il messaggio o parte di esso
Old 19-12-2008, 13:05   #8
tomminno
Senior Member
 
Iscritto dal: Oct 2005
Messaggi: 3306
Io farei qualcosa del genere (in C#):
Codice:
class PizzaFactory
{
    public PizzaFactory()
    {
         InitPizzaMaker();
    }
    public IPizza MakePizza(string pizzaName)
    {
          return pizzaMaker[pizzaName.ToLower()];
    }
    private void InitPizzaMaker()
    {
        pizzaMaker ["margherita"] = PizzaMaker<Margherita>;
        pizzaMaker ["napoli"] = PizzaMaker<Napoli>;
        //...
    }

    T PizzaMaker<T>() where T : IPizza, new()
    {
        return new T();
    }

    private delegate IPizza MakePizza();
    private Dictionary<string, MakePizza> pizzaMaker = new Dictionary<string, MakePizza>();
}

Ultima modifica di tomminno : 19-12-2008 alle 13:10.
tomminno è offline   Rispondi citando il messaggio o parte di esso
Old 19-12-2008, 13:44   #9
marco.r
Senior Member
 
Iscritto dal: Dec 2005
Città: Istanbul
Messaggi: 1817
Quote:
Originariamente inviato da banryu79 Guarda i messaggi
Io ti linko questo thread, magari ti è utile.
L'importante e' non esagerare
http://discuss.joelonsoftware.com/de...el.3.219431.12
__________________
One of the conclusions that we reached was that the "object" need not be a primitive notion in a programming language; one can build objects and their behaviour from little more than assignable value cells and good old lambda expressions. —Guy Steele
marco.r è offline   Rispondi citando il messaggio o parte di esso
Old 19-12-2008, 14:02   #10
banryu79
Senior Member
 
L'Avatar di banryu79
 
Iscritto dal: Oct 2007
Città: Padova
Messaggi: 4131
Quote:
Originariamente inviato da marco.r Guarda i messaggi
La conoscevo già, spassosissimo (la FactoryFactoryFactory è comodissima per costruire una AbstractToolFactoryFactory che verrà poi utilizzata per costruire una HammerFactory, giustappunto quello che ci serviva per avere un semplice, stramaledetto, Hammer)

I Design Pattern non sono legge, sono molto comodi e utili, ma non bisogna farsi prendere la mano
__________________

As long as you are basically literate in programming, you should be able to express any logical relationship you understand.
If you don’t understand a logical relationship, you can use the attempt to program it as a means to learn about it.
(Chris Crawford)
banryu79 è offline   Rispondi citando il messaggio o parte di esso
Old 19-12-2008, 14:55   #11
mcaisco
Member
 
Iscritto dal: Jun 2006
Messaggi: 117
Se ho capito l'idea ti Tomminno, allora è un'approccio che ho già visto in qualche esempio. Sostanzialmente l'idea credo sia quella di dichiarare nelle Factory più generale un campo che rappresenti l'insieme delle Factory specializzate esistenti (nel caso viene implementato in C# con un Dictionary, ma può essere un qualunque array, arraylist, hashmap...).
Però credo che il punto centrale sia la dichiarazione della classe Factory generale come classe concreta e non come classe astratta o interfaccia, come credo sia indicato dalle linee guida per questo pattern.

Il fatto è che la factory generale deve fungere da factory generale appunto! Cioè deve contenere tutti i metodi che devono essere comunque reimplementati nelle factory concrete derivate da questa. Se non si dichiara la factory generale come astratta o interfaccia, le factory derivate credo siano svincolate da questo dovere di implemtare i metodi specificati come astratti. O no? Altrimenti in effetti che utilità avrebbe usare una classe astratta/interfaccia per la factory generale?
mcaisco è offline   Rispondi citando il messaggio o parte di esso
Old 19-12-2008, 16:01   #12
tomminno
Senior Member
 
Iscritto dal: Oct 2005
Messaggi: 3306
Quote:
Originariamente inviato da mcaisco Guarda i messaggi
Se ho capito l'idea ti Tomminno, allora è un'approccio che ho già visto in qualche esempio. Sostanzialmente l'idea credo sia quella di dichiarare nelle Factory più generale un campo che rappresenti l'insieme delle Factory specializzate esistenti (nel caso viene implementato in C# con un Dictionary, ma può essere un qualunque array, arraylist, hashmap...).
Però credo che il punto centrale sia la dichiarazione della classe Factory generale come classe concreta e non come classe astratta o interfaccia, come credo sia indicato dalle linee guida per questo pattern.
Quello a cui fai riferimento te è l'Abstract Factory, io ho postato un esempio di Factory Method.
L'Abstract Factory lo usi in un caso del genere (sempre prendendo spunto dalla pizza):
Codice:
List<AbstractFactory> abstractFactory = new List<AbstractFactory>();
abstractFactory.Add(FactoryPizza);
abstractFactory.Add(FactoryStarter);
abstractFactory.Add(FactoryDessert);
Dinner dinner = new Dinner();
dinner.Cook(abstractFactory);
L'Abstract Factory serve per avere famiglie di Factory Method, cioè se vuoi creare delle pizze, degli antipasti, dei dolci,...
Ognuno di questi factory sarà internamente implementato come singolo Factory Method.
tomminno è offline   Rispondi citando il messaggio o parte di esso
Old 20-12-2008, 14:41   #13
0rph3n
Senior Member
 
L'Avatar di 0rph3n
 
Iscritto dal: Apr 2005
Città: Resana - TV
Messaggi: 960
io l'ho reiterpretato così:

Codice:
public interface IIdentificabile
{
    Int32 ID
    {
        get;
        set;
    }
}

public static class FabbricaGenerica<T>() where T:IIdentificabile
{
    private LinkedList<T> istanze = new LinkedList<T>();

    public static T CreaIstanza(Int32 id)
    {
        T istanza = Activator.CreateInstance<T>();
        istanza.ID = id;
        FabbricaGenerica<T>.istanze.AddLast(istanza);
        return istanza;
    }

    private static T CercaIstanza(Int32 id)
    {
        // Implementare l'algoritmo desiderato per cercare all'interno della LinkedList
    }

    public static T RecuperaIstanza(Int32 id)
    {
        T istanza = null;
        istanza = FabbricaGenerica<T>.CercaIstanza(Int32 id);

        if (istanza == null)
        {
            istanza = FabbricaGenerica<T>.CreaIstanza(id);
        }

        return istanza;
    }
}
...che ne dite?
0rph3n è offline   Rispondi citando il messaggio o parte di esso
Old 20-12-2008, 17:18   #14
gugoXX
Senior Member
 
L'Avatar di gugoXX
 
Iscritto dal: May 2004
Città: Londra (Torino)
Messaggi: 3692
Consiglio per questo problema di non costruire un nuovo Generic, dato che in teoria se ne potrebbe fare a meno, sfruttando la sola ereditarieta' e polimorfismo.
__________________
Se pensi che il tuo codice sia troppo complesso da capire senza commenti, e' segno che molto probabilmente il tuo codice e' semplicemente mal scritto.
E se pensi di avere bisogno di un nuovo commento, significa che ti manca almeno un test.
gugoXX è offline   Rispondi citando il messaggio o parte di esso
Old 23-12-2008, 08:15   #15
mcaisco
Member
 
Iscritto dal: Jun 2006
Messaggi: 117
Beh comunque vorrei chiarire che il problema delle pizze era solo per introdurre la questione e avere qualcosa su cui lavorare.
Il mio intento è capire come funzionano i pattern factory (method e abstract).
Se avete un esempio più calzante che chiarisca bene come funzionano questi pattern siete caldamente invitati a discuterne!!!
mcaisco è offline   Rispondi citando il messaggio o parte di esso
 Rispondi


Recensione Samsung Galaxy Z Fold7: un grande salto generazionale Recensione Samsung Galaxy Z Fold7: un grande sal...
The Edge of Fate è Destiny 2.5. E questo è un problema The Edge of Fate è Destiny 2.5. E questo ...
Ryzen Threadripper 9980X e 9970X alla prova: AMD Zen 5 al massimo livello Ryzen Threadripper 9980X e 9970X alla prova: AMD...
Acer TravelMate P4 14: tanta sostanza per l'utente aziendale Acer TravelMate P4 14: tanta sostanza per l'uten...
Hisense M2 Pro: dove lo metti, sta. Mini proiettore laser 4K per il cinema ovunque Hisense M2 Pro: dove lo metti, sta. Mini proiett...
Sharkoon punta sui case a basso costo, m...
La tua rete Wi-Fi fa pena? Questi FRITZ!...
Amazon, un weekend di fuoco per gli scon...
Ancora 3 smartwatch Amazfit in forte sco...
Sharkoon A60 RGB: dissipatore ad aria du...
HONOR 400 Pro a prezzo bomba su Amazon: ...
Offerte da non perdere: robot aspirapolv...
Apple Watch e Galaxy Watch ai minimi sto...
Il rover NASA Perseverance ha ''raccolto...
NASA e ISRO hanno lanciato il satellite ...
Switch 2 ha venduto 5,82 milioni di cons...
Assassin's Creed Black Flag Remake: le m...
Cosa ci fa una Xiaomi SU7 Ultra alle por...
Promo AliExpress Choice Day: prezzi stra...
Nostalgico, ma moderno: il nuovo THEC64 ...
Chromium
GPU-Z
OCCT
LibreOffice Portable
Opera One Portable
Opera One 106
CCleaner Portable
CCleaner Standard
Cpu-Z
Driver NVIDIA GeForce 546.65 WHQL
SmartFTP
Trillian
Google Chrome Portable
Google Chrome 120
VirtualBox
Tutti gli articoli Tutte le news Tutti i download

Strumenti

Regole
Non Puoi aprire nuove discussioni
Non Puoi rispondere ai messaggi
Non Puoi allegare file
Non Puoi modificare i tuoi messaggi

Il codice vB è On
Le Faccine sono On
Il codice [IMG] è On
Il codice HTML è Off
Vai al Forum


Tutti gli orari sono GMT +1. Ora sono le: 12:00.


Powered by vBulletin® Version 3.6.4
Copyright ©2000 - 2025, Jelsoft Enterprises Ltd.
Served by www3v