Fabrik Entwurfsmuster in Cpp



  • Hallo,

    ich frage mich wofür man das Fabrik Entwurfsmuster benötigt und einsetzt und wie man es in C++ richtig umsetzt. Im Internet schaute ich ein Video wo es für Java erklärt wird. Dabei wurden die Objekte des Entwurfsmuster in ein Paket gesteckt und ihre Konstruktoren auf Protected gesetzt, um Objekte ausschließlich über die Fabrik zu erstellen.

    Ich selbst hab es auch mal probiert und bin am Schlüsselwort Protected gescheitert und hab nun eine Pseudofactory, wenn überhaupt, weil ich das Objekt Soldat immernoch frei über den Konstruktor erstellen kann, weil ich das Schlüsselwort Protected im Namespace nicht verwenden darf und ich Zugriffsprobleme bekomme.

    Mein Ziel war es, dass Soldaten ausschließlich über die Kaserne und Grundausbildungsmethode erstellt werden können.

    Gruß
    M.K.

    #include <string>
    #include <iostream>
    using namespace std;
    class Zivilist {
                            private:
                            string name;
                            //Konstruktor
                            public:
                            Zivilist(string name) {
                            this->name = name;
                            }
                            public:
                            string getName()
                            {
                                    return name;
                            }
            };
    namespace Bundeswehr
    {
            class Soldat {
                    protected:
                    string name;
                    string typ;
                     //Konstruktor der abstrakkten Klasse Soldat
                    public:
                            virtual void printStatus(){cout << "Der Soldat heißt "+ this->name + " und ist " + this->typ+".\n";}
                    };
    
                    class Infanterist : public Soldat
                    {
                            public:
                                    Infanterist(string name){
                                    this->name = name;
                                    this->typ = "Infanterist";
                            }
                    };
    
                    class Artillerist : public Soldat {
                            public:
                                    Artillerist(string name)
                                    {
                                            this->name = name;
                                            this->typ = "Artillerist";
                                    }
                    };
    
                    class Kaserne {
                            public:
                                    static Soldat Grundausbildung(Zivilist rekrut, string typ) {
                                    if (typ == "infanterist")
                                    {
                                            Soldat *soldat = new Infanterist(rekrut.getName());
                                            return *soldat;
                                    }
                                    if (typ == "artillerist")
                                    {
                                            Soldat *soldat = new Artillerist(rekrut.getName());
                                            return *soldat;
                                    }
                            }
    
                    };
    }
    
    int main()
    {
            Zivilist rekrut("Tilo");
            Zivilist rekrut2("Joe");
    
            Bundeswehr::Soldat soldat;
            Bundeswehr::Soldat soldat2;
    
            soldat = Bundeswehr::Kaserne::Grundausbildung(rekrut, "infanterist");
            soldat2 = Bundeswehr::Kaserne::Grundausbildung(rekrut2, "artillerist");
    
            soldat.printStatus();
      soldat2.printStatus();
            return 0;
         }
    

    Okay die Lösung ist friendclass Kaserne; Und anschließend kann man den Konstruktor von Public auf Protected ändern.


  • Mod

    Du machst ja nirgendwo, was du beschreibst. Der Konstruktor von Soldat ist bei dir eben nicht protected, sondern public.

    Weiterhin scheinst du mit folgenden Dingen Schwierigkeiten zu haben, die eigentlich Grundlage für dieses Thema sind:
    -Wo genau wird ein Objekt erstellt?
    -Wie wird ein Objekt erstellt?
    -Wie funktioniert die Erstellung von Klassen im Falle von Vererbung?
    -Was genau bedeuten private, protected, public?

    Dein Problem ist, dass in deinem Code lauter Objekte erstellt werden, von denen du wahrscheinlich gar nicht wolltest, dass sie erzeugt werden. Und da diese Erstellung natürlich einen Konstruktor brauchte, hast du, anstatt die Fehler zu beseitigen, stattdessen die Konstruktoren wieder public gemacht. Womit der ganze Sinn der Sache dahin war.

    So sieht es aus, wenn ich das mal flott überarbeite:

    #include <string>
    #include <iostream>
    using namespace std;
    
    class Zivilist 
    {
    private:
      string name;
    public:
      Zivilist(string name) : name(name) { }
      string getName()
      {
        return name;
      }
    };
    
    namespace Bundeswehr
    {
      class Soldat 
      {
      private:
        string name;
        string typ;
      protected:
        Soldat(string name, string typ): name(name), typ(typ) { }
      public:
        void printStatus(){cout << "Der Soldat heißt "+ this->name + " und ist " + this->typ+".\n";}
      };
    
      class Infanterist : public Soldat
      {
      public:
        Infanterist(string name): Soldat(name, "Infanterist") { }
       };
    
      class Artillerist : public Soldat 
      {
      public:
        Artillerist(string name): Soldat(name, "Artillerist") { }
      };
    
      class Kaserne 
      {
      public:
        static Soldat Grundausbildung(Zivilist rekrut, string typ) 
        {
          if (typ == "infanterist")
            {
              return Infanterist(rekrut.getName());
            }
          if (typ == "artillerist")
            {
              return Artillerist(rekrut.getName());
            }
          // Was eigentlich, wenn nichts von alledem?
        } 
      };
    }
    
    int main()
    {
      Zivilist rekrut("Tilo");
      Zivilist rekrut2("Joe");
    
      Bundeswehr::Soldat soldat = Bundeswehr::Kaserne::Grundausbildung(rekrut, "infanterist");
      Bundeswehr::Soldat soldat2 = Bundeswehr::Kaserne::Grundausbildung(rekrut2, "artillerist");
    
      soldat.printStatus();
      soldat2.printStatus();
    
      // Folgendes geht hingegen nicht:  
      Bundeswehr::Soldat soldat3("Manni", "Fallschirmspringer");
    }
    

    Das sollte wohl schon eher dem näher kommen, was du wolltest.

    Es ist noch wichtig zu erwähnent, dass derzeit nur Soldat-Objekte erstellt werden, die das entsprechende typ-Member auf "Artillerist" bzw. "Infanterist" gesetzt haben. Aber sie sind nicht vom Objekttyp Artillerist bzw. Infanterist ! Diese Information geht derzeit verloren, was derzeit aber auch nicht weiter schlimm ist, da diese beiden abgeleiteten Klassen der Soldatenklasse nichts hinzufügen. Aber wenn die Information erhalten bleiben soll, dann muss man stattdessen ein polymorphes Design wählen.



  • Dieser Thread wurde von Moderator/in SeppJ aus dem Forum Rund um die Programmierung in das Forum C++ (alle ISO-Standards) verschoben.

    Im Zweifelsfall bitte auch folgende Hinweise beachten:
    C/C++ Forum :: FAQ - Sonstiges :: Wohin mit meiner Frage?

    Dieses Posting wurde automatisch erzeugt.



  • // Interfaces, die einen Satz von Objekttypen definieren
    class ICivilian
    {
       ...
    };
    
    class ISoldier
    {
       ...
    };
    
    class IFactory
    {
    poublic:
       std::unique_ptr<ICivilian> create_civilian() const = 0;
       std::unique_ptr<ISoldier> create_soldier() const = 0;
    };
    
    // Konkrete Implementierung eines Objekttyp-Satzes
    class BundeswehrCivilian : public ICivilian
    {
       ...
    };
    
    class BundeswehrSoldier : public ISoldier
    {
      ...
    };
    
    class BundeswehrFactory : public IFactory
    {
    public:
       std::unique_ptr<ICivilian> create_civilian() const
       {
          return std::make_unique( new BundeswehrCivilian() );
       }
    
       std::unique_ptr<ISoldier> create_soldier() const
       {
          return std::make_unique( new BundeswehrSoldier() );
       }
    };
    
    // Konkrete Implementierung eines Objekttyp-Satzes
    class USArmyCivilian : public ICivilian
    {
       ...
    };
    
    class USArmySoldier : public ISoldier
    {
       ...
    };
    
    class USArmyFactory : public IFactory
    {
    public:
       std::unique_ptr<ICivilian> create_civilian() const
       {
          return std::make_unique( new USArmyCivilian() );
       }
    
       std::unique_ptr<ISoldier> create_soldier() const
       {
          return std::make_unique( new USArmySoldier() );
       }
    };
    
    namespace ArmyType
    {
       enum Type_t
       {
          Bundeswehr,
          USArmy
       };
    }
    
    std::unique_ptr<IFactory> create_factory( ArmyType::Type_t Type )
    {
       if( Type == ArmyType::Bundeswehr ) return std::make_unique( new BundeswehrFactory() );
       else if( Type == ArmyType::USArmy ) return std::make_unique( new USArmyFactory );
       assert( false );
    }
    
    int main()
    {
       // Armeetyp bestimmen, zb. aus Konfigurationsdatei, und passende Factory erzeugen
       std::unique_ptr<IFactory> Factory = create_factory( Configuration.ArmyType );
    
       // Zivilisten und Soldaten erzeugen (nur gegen Interfaces programmiert). Ab
       // hier weiß man nicht mehr, welcher konkrete Typ hinter c oder s steckt.
       std::unique_ptr<ICivilian> c = Factory->create_civilian();
       std::unique_ptr<ISoldier> s = Factory->create_soldier();
    }
    

    Der Zweck von solchen Factories ist es, dass zwischen kompletten Objekttyp-Sätzen umgeschaltet werden kann, ohne den Client Code anzufassen. Es können ohne großen Aufwand neue Zivilisten-/Soldatentypen ergänzt werden, solange sie die Interfaces implementieren.


Log in to reply