Wie Strategien (Entwurfsmuster) an basisklassen weitergeben



  • Hallo zusammen,

    wenn ich eine Basisklasse habe, die mehrere verschiedene Strategien benutzt, wie würdet ihr dann die konkreten instanzen der strategien an die Basisklasse übergeben?

    Hier mal ein Beispiel:

    Ich habe eine Klasse Body, dessen genaues verhalten durch 3 strategien festgelegt wird:
    -JumpStrategy
    -AccelerationStrategy
    -FixtureStrategy

    JumpStrategy und AccelerationStrategy legen dabei fest, ob und wie ein Body springen kann und wie er beschleunigt (z.B. lineare beschleunigung oder sofort von 0 auf maxspeed ohne zeitverzögerung)
    Die FixtureStrategy ist dafür da, die Struktur des Bodies (z.B. ein Polygon) zu erstellen, und später evtl. Änderungen daran vorzunehmen.
    Als Strategies können auch Nullobjekte benutzt werden, wenn z.B. ein Body benötigt wird, der nicht springen kann.

    Ich brauche viele verschiedene Typen von Bodies, deswegen benutze ich die Strategien. Die Strategien sollen auch zur Laufzeit auswechselbar sein und ich will das auch in anderen programmiersprachen implementieren können, deswegen mache ich das nicht mit template/policies.

    Die Basisklasse benutzt je eine instanz der drei strategien und legt die interaktion mit den strategien fest. Evtl. sollen andere Klassen abgeleitet werden, die das verhalten zusätzlich ändern können.
    Wichtig zu wissen ist auch, dass die FixtureStrategy am besten schon im Basisklassenkonstruktor verfügbar sein sollte, weil dort dann eine Methode CreateFixtures() aufgerufen wird.

    Jetzt frage ich mich - wie gebe ich die konkreten Instanzen der Strategien am besten an die Basisklasse weiter?

    Mir fallen dazu 3 Möglichkeiten ein:
    (Der übersichtlichkeithalber habe ich jetzt raw pointer verwendent, unique_ptr wären evtl. besser geeignet.

    class Body
    {
    //Body hat noch einige methoden, die die strategien verwenden, die lasse ich aber im weiteren weg
    public:
       Body(FixtureStrategy * fixtureStrat, AccelerationStrategy * accelerationStrat, JumpStrategy * jumpStrat);
    protected:
       //zugriff für abgeleitete klassen
       FixtureStrategy & getFixtureStrat();
       AccelerationStrategy & getAccelerationStrat();
       JumpStrategy & getJumpStrat();    
    private:
        FixtureStrategy * fixtureStrat;
        AccelerationStrategy * accelerationStrat;
        JumpStrategy * jumpStrat;
    };
    
    class Body
    {
    protected:
        FixtureStrategy * fixtureStrat;
        AccelerationStrategy * accelerationStrat;
        JumpStrategy * jumpStrat;
    }
    
    class Body
    {
    protected:
       virtual FixtureStrategy & getFixtureStrat() = 0;
       virtual AccelerationStrategy & getAccelerationStrat() = 0;
       virtual JumpStrategy & getJumpStrat() = 0;    
    };
    

    1.:
    Vorteile:
    - Alle strategien werden sofort initialisiert und CreateFixtures kann vom Baisklassenkonstruktor aufgerufen werden
    - Sofern das verhalten nicht weiter angepasst werden muss, kann man durch factory methoden instanzen von Body mit verschiedenen konkreten policies erstellen

    Nachteile;
    - Abgeleitete Klassen verlieren die Typinformation, wenn sie per getter auf die strategies zugreifen wollen und müssen deswegen evtl. casten
    - Das initialisieren und weiterreichen der Argumente an die Basisklasse wird sehr schwierig, besonders falls die konkreten strategies referenzen aufeinander brauchen (was vorkommen kann).

    2.:
    Vorteile:
    - Für Abgeleitete Klassen wird es einfacher, strategies die aufeinander aufbauen zu verwenden

    Nachteile;
    - Im Basisklassenkonstruktor sind die strategies noch nicht gesetzt und deshalb kann z.B. CreateFixtures() von dort nicht aufgerufen werden
    - Es wird nicht sichergestellt, dass alle strategies initialisiert werden
    - Für jede Kombination an Strategies muss von der Basisklasse abgeleitet werden

    3.:
    Vorteile:
    - Abgeleitete Klassen behalten Typinformationen zu ihren strategies und müssen diese nicht mehr dynamisch anlegen
    - Es wird sichergestellt, dass alle strategies bedient werden (getter müssen überschrieben werden)

    Nachteile;
    - Im Basisklassenkonstruktor kann nicht auf die strategies zugegriffen werden (CreateFixtures ist dort nicht möglich)
    - Zum Zugriff auf die strategien von der Basisklasse werden virtuelle methoden benutzt (das habe ich nur der vollständigkeit wegen erwähnt, ansonsten finde das nicht wirklich relevant)
    - Für jede Kombination an Strategies muss von der Basisklasse abgeleitet werden

    Was findet ihr davon sinnvoll? Kennt ihr noch weitere Vor-/Nachteile und/oder weitere alternativen? Wie würdet ihr das machen?

    Vielen Dank schonmal für eure Hilfe!


Anmelden zum Antworten