Single Responsibility Principle - Richtig verstanden?



  • Heya Leute!

    Ich wollte durch euch mein neu erworbenes Wissen in die richtigen Bahnen einleiten und dementsprechend festigen. Ich bin halt in erster Linie unsicher ob ich das Thema richtig erkannt habe und darum frage ich lieber noch paar mal nach bevor ich es wirklich in meinem Hirn serialisiere ;P

    Es geht um das SRP (Single Responsibility Principle) bzw dem "S" der SOLID Principles. Quelle des Stoffes: https://www.youtube.com/watch?v=gwIS9cZlrhk

    Ich habe verstanden das eine Klasse wirklich nur einen Aufgabenbereich haben sollte - und sich dementsprechend nur ändern darf wenn dieser Bereich grundlegend geändert wird.

    Als Beispiel nehme ich mal meine "Weapon.cs" Klasse meines 2D Spiels.

    public class Weapon
        {
            private readonly int ammo;
            private readonly int color;
            private readonly int weaponType;
    
            public Weapon()
            {
                this.ammo = 10;
                this.color = 3;         // theor. Farbcode
                this.weaponType = 1;    // theor. Typcode
            }
    
            public void shootWeapon()
            {
                // code...
            }
    
            public void reloadWeapon(int amount)
            {
                // code...
            }
    
            public void changeType(int type)
            {
                //code
            }
        }
    

    Das Ganze so abgewandelt wie ich das SRP verstanden habe, diesmal auch mit Vererbung.

    public class Weapon
        {
            private readonly int ammo;
            private readonly int color;
            private readonly int type;
    
            public Weapon()
            {
                this.ammo = 10;
                this.color = 3;
                this.type = 1;
            }
        }
    
        public class WeaponShooter : Weapon
        {
            public WeaponShooter() { }
    
            public void shootWeapon()
            {
                // code...
            }
        }
    
        public class WeaponReloader : Weapon
        {
            public WeaponReloader() { }
    
            public void reloadWeapon(int ammo) 
            {
                // code...
            }
        }
    
        public class WeaponChanger : Weapon
        {
            public WeaponChanger() { }
    
            public void changeWeapon(int type)
            {
                // code...
            }
        }
    

    Nun sind alle Klasse auf einen Verantwortungsbereich beschränkt. WeaponReloader z.b. kümmert sich nur um das Nachladen einer Waffe.

    Ehrlich gesagt werde ich mit dem Principle nicht ganz warm. Auch weil ich glaube das ich das Ganze persönlich zu extrem ausreize. Jedoch hat das Video auf Youtube - welches ich oben gepostet habe - eine Klasse ähnlich hardcore aufgesplittet und drei Klassen, wo ich gesagt hätte, lass das Teil doch zusammen.

    Wenn das wirklich eine so wichtige Richtlinie ist, verstehe ich kaum noch wieso manche Klassen mehr als eine Methode haben 😕 (ausgenommen Überladungen, die ja noch vereinbar sind mit einem Verantworungsbereich).

    Ich würde euch sehr danken wenn ich mich ein wenig wachrüttelt 🙂

    gruß Charlie



  • Eine Waffe hat die Schnittstellen Reload, Shoot usw.

    Das zweite Design ist irgendwie falsch. Weil du bei der Vererbung gegen die "ist-eine"-Regel verstoßen hast!

    Reloader ist-eine Weapon?

    Was soll das sein? Ich vermute, da geht es eher um das Strategie-Pattern für ein Verhalten eines Objektes.

    Also, das Zuständigkeitsprinzip ist was anderes. Jede Klasse, also jeder Typ, macht etwas. Eine Waffe kann schießen und kann nachgeladen werden. Das passiert in einer Klasse.

    Aber für die Munition müsstest du eine neue Klasse erstellen.

    // Interface Klasse
    class Munition;
    
    // Interface Klasse
    class Waffe 
    {
    public:
            void feuer(); 
            void nachladen(Munition &m);
            bool leer();
    };
    

    So hast du für jeden Typ (Munition und Waffe) eine eigene Klasse. WIE das Nachladen passiert, WIE das Schießen passiert, kannst du direkt in die jeweilige Unterklasse implementieren.



  • Das was man machen kann, ist den Algorithmus Reloader, Changer usw. in eine eigene Klasse auslagern. Aber ganz bestimmt nicht als Typ Weapon! (is-a Regel!)

    Aber auch dann würdest du diese Algorithmen z.B. als Strategie-Pattern in der Weapon einbauen.

    Ach ja, was soll das typ-Member in deiner Weapon? Das sieht nicht nach OOD aus.

    Wenn du eine Schrotflinte und einen Revolver hast, dann machst du eine Vererbung:
    Pumpgun is-a Weapon.
    Flammenwerfer is-a Weapon.

    class Waffe
    {
    public:
        void feuer();
        void nachladen(Munition &m);
        bool leer();    
    private: 
        Color c;
    };
    
    // Konkreter Typ: hier feuer und nachladen für Pumpgun implementieren
    class Pumpgun : public Waffe
    {};
    
    // Konkreter Typ...
    class Flammenwerfer: public Waffe
    {};
    

    Dann hast du unterschiedliche Munition, mit denen du die Waffen nachladen kannst:

    class Munition
    {};
    
    class PumpgunPatrone : public Munition
    {};
    
    class Benzin : public Munition
    {};
    

    Wenn man Benzin in die Pumpgun einfüllt, passiert bei der feuer()-Funktion nichts! kaputt! 😃 Oder beim nachladen kommt ne Exception.

    EDIT: Patrone durch allgemeine Munition ersetzt.


Anmelden zum Antworten