Visualizzazione dei risultati da 1 a 5 su 5

Discussione: [c++]abstract factory

  1. #1
    Utente di HTML.it
    Registrato dal
    Jun 2003
    Messaggi
    4,826

    [c++]abstract factory

    ciao.
    Sto leggendo il libro della gang of four e ho una domanda sull'abstract factory:
    codice:
    class MazeFactory {
    public:
    MazeFactory();
    virtual Maze* MakeMaze() const
    { return new Maze; }
    virtual Wall* MakeWall() const
    { return new Wall; }
    virtual Room* MakeRoom(int n) const
    { return new Room(n); }
    virtual Door* MakeDoor(Room* r1, Room* r2) const
    { return new Door(r1, r2); }
    };
    .
    .
    Maze* MazeGame::CreateMaze (MazeFactory& factory) {
    Maze* aMaze = factory.MakeMaze();
    Room* r1 = factory.MakeRoom(1);
    Room* r2 = factory.MakeRoom(2);
    Door* aDoor = factory.MakeDoor(r1, r2);
    aMaze->AddRoom(r1);
    adesso se voglio creare ad es una magic maze basta che creo una concrete factory ereditando da mazefactory cosi:
    codice:
    class EnchantedMazeFactory : public MazeFactory {
    public:
    EnchantedMazeFactory();
    virtual Room* MakeRoom(int n) const
    { return new EnchantedRoom(n, CastSpell()); }
    virtual Door* MakeDoor(Room* r1, Room* r2) const
    { return new DoorNeedingSpell(r1, r2); }
    protected:
    Spell* CastSpell() const;
    };
    e da programma:
    codice:
    MazeGame game;
    EnchantedMazeFactory factory;
    game.CreateMaze(factory);
    fin qui ho capito.
    Il mio problema non riguarda tanto il pattern , ma l'uso delle classi. se ho ad es un enchanted room nel mio labirinto come faccio a sapere se è di tipo enchanted o normale e chiamare la funzione castspell di conseguenza(solo se è di tipo enchancted)?
    Sono abituato ad usare il polimorfismo per questo , ma non riesco a capire come nell'esempio.
    PEnso che la chaive sia in questa riga:
    return new EnchantedRoom(n, CastSpell()); e nel concetto di downcasting che per altro non ho capito bene.

  2. #2
    Utente di HTML.it L'avatar di shodan
    Registrato dal
    Jun 2001
    Messaggi
    2,381
    Devi usare un dynamic_cast per il downcasting dei tipi polimorfici.
    Nel caso del labirinto si usa cosi:

    codice:
    Room* r1 = factory.MakeRoom(1);
    EnchantedRoom* er = dynamic_cast<EnchantedRoom*>(r1);
    if (er) er->CastSpell();
    Il dynamic_cast controlla nella vtable se il puntatore r1 è creato da una EnchantedRoom e se l'esito è positivo effettua il cast, in caso negativo restituisce NULL.

  3. #3
    Utente di HTML.it
    Registrato dal
    Jun 2003
    Messaggi
    4,826
    Grazie Shodan.
    Ma non capisco bene: questo metodo non va contro il normale polimorfismo?
    Voglio dire deve essere l'oggetto a reagire di conseguenza alla chiamata , e non io che reagisco se l'oggetto è del tipo xxx.
    Altra cosa:
    perchè mazefactory non è astratta?

  4. #4
    Utente di HTML.it L'avatar di shodan
    Registrato dal
    Jun 2001
    Messaggi
    2,381
    Originariamente inviato da giuseppe500
    Grazie Shodan.
    Ma non capisco bene: questo metodo non va contro il normale polimorfismo?
    Voglio dire deve essere l'oggetto a reagire di conseguenza alla chiamata , e non io che reagisco se l'oggetto è del tipo xxx.
    In un certo senso hai ragione. Trovare troppi dynamic_cast in giro per il codice può essere indice di pessima progettazione (oltre al fatto che è il cast più lento), però in casi come questo è utile. Se hai 99 stanze non incantate e solo una si, non ha molto senso prevedere una CastSpell dove non occorre (ma questo è comunque opinabile).

    Il punto è che a volte può capitare di ricevere un puntatore a una classe base, che non si deve e/o non si può modificare e il dynamic_cast è l'unico modo sicuro per accedere ai metodi della classe derivata.
    Inoltre è l'unico cast in grado di percorrere le gerarchie di derivazione e controllare che un dato puntatore appartenga ad un ramo di derivazione piuttosto che ad un altro.

    Ti consiglio di partire da qui per un approfondimento.
    http://www.cs.huji.ac.il/labs/parall...e/tic0264.html

    Altra cosa:
    perchè mazefactory non è astratta?
    Ma MazeFactory è astratta, solo che implementa un comportamento di default.
    E' una questione di sfumature. Dal mio punto di vista una classe è un'interfaccia astratta se, e solo se, tutti i metodi sono virtual e non contiene dati membro. Lasciare un comportamento di default o renderla un'interfaccia astratta pura (con i metodi =0) e solo un dettaglio implementativo.
    Di certo nel secondo caso (con i metodi =0) si mette subito in chiaro che quella è solo un'interfaccia da cui si può solo derivare e niente altro.

  5. #5
    Utente di HTML.it
    Registrato dal
    Jun 2003
    Messaggi
    4,826
    grazie Shodan.
    Ho trovato quest ' implementazione dell'abstract factory che mi fa capire meglio:
    codice:
    namespace DesignPatterns.AbstractFactory
    {
        public interface IShape 
        {
            void Print();
        }
    
        public class Rectangle : IShape
        {
            public virtual void Print()
            {
                Console.WriteLine("Rectangle");
            }
        }
    
        public class Circle : IShape
        {
            public virtual void Print()
            {
                Console.WriteLine("Circle");
            }
        }
    
        public interface IShapeFactory
        {
            Rectangle CreateRectangle();
            Circle CreateCircle();
        }
    
        public class MyRectangle : Rectangle
        {
            public override void Print()
            {
                Console.WriteLine("MyRectangle");
            }
        }
    
        public class MyCircle : Circle
        {
            public override void Print()
            {
                Console.WriteLine("MyCircle");
            }
        }
    
        public class MyShapeFactory : IShapeFactory
        {
            public Rectangle CreateRectangle()
            {
                return new MyRectangle();
            }
    
            public Circle CreateCircle()
            {
                return new MyCircle();
            }
        }
    in questo caso posso derivare ad es da rectangle e utilizzare una funzione polimorfica nel caso print() che se è myrectangle agisce in un modo , myrectangle2 in un altro e cosi' via.
    codice:
        public class Program
        {
            static void Main(string[] args)
            {
                IShapeFactory fac = new MyShapeFactory();
                Circle c = fac.CreateCircle();
                Rectangle r = fac.CreateRectangle();
                c.Print();
                r.Print();
                Console.ReadLine();
            }
        }
    }
    quindi pensavo nel nostro esempio dei labirinti di dichiarare nella classe base room(che nell es. è rectangle) un castspell e in enchantedroom (myrectangle) faccio l'override del metodo in modo che non fa niente se è una room normale ma in enchanted room esegue giustamente il metodo corrispondente.

    ed effettivamente mi ritrovo a questo punto:

    però in casi come questo è utile. Se hai 99 stanze non incantate e solo una si, non ha molto senso prevedere una CastSpell dove non occorre (ma questo è comunque opinabile).
    Adesso che ho letto sono conscio che ho molto da imparare da Bruce Eckel's Thinking in C++, 2nd Ed
    C'è tanta di quella roba da capire e leggere che neanche uno pensa.
    grazie.

Permessi di invio

  • Non puoi inserire discussioni
  • Non puoi inserire repliche
  • Non puoi inserire allegati
  • Non puoi modificare i tuoi messaggi
  •  
Powered by vBulletin® Version 4.2.1
Copyright © 2026 vBulletin Solutions, Inc. All rights reserved.