Matthias Apsel: Stein-Schere-Papier-Echse-Spock in OOP

0 55

Stein-Schere-Papier-Echse-Spock in OOP

Matthias Apsel
  • programmiertechnik
  1. 0
    Whouzuo
    1. 0
      T-Rex
      1. 0
        Whouzuo
  2. 0
    T-Rex
    1. 0

      Stein-Schere-Papier-Echse-Spock

      Auge
      • menschelei
  3. 0
    M.
  4. 0
    Encoder
    1. 0
      Matthias Apsel
      1. 0
        Encoder
        1. 0
          Matthias Apsel
          1. 0
            Whouzuo
            1. 0
              Matthias Apsel
              1. 0
                Whouzuo
        2. 0
          Matthias Apsel
  5. 0
    T-Rex
    1. 0
      Whouzuo
      1. 0
        Encoder
        1. 0
          Whouzuo
          1. 0
            Encoder
            1. 0
              Whouzuo
              1. 0
                Encoder
                1. 0
                  Matthias Apsel
                2. 0
                  Whouzuo
                  1. 0
                    Matthias Apsel
                    1. 0
                      Whouzuo
                    2. 0
                      Whouzuo
                      1. 0
                        Matthias Apsel
      2. 0
        Matthias Apsel
        1. 0
          Whouzuo
          1. 0
            Matthias Apsel
            1. 0
              Whouzuo
              1. 0
                Matthias Apsel
                1. 0
                  Whouzuo
                  1. 0
                    Matthias Apsel
              2. 0
                dedlfix
                1. 0
                  dedlfix
                2. 0
                  Whouzuo
      3. 0
        T-Rex
    2. 0
      T-Rex
      1. 0
        Matthias Apsel
  6. 3
    Der-Dennis
    1. 3
      Der-Dennis
      1. 0
        Whouzuo
        1. 0
          Der-Dennis
          1. 0
            Whouzuo
            1. 0
              Der-Dennis
          2. 0

            Stein-Schere-Papier-Echse-Spock in OOP (Teil 2)

            Whouzuo
            1. 0
              Der-Dennis
              • menschelei
    2. 0
      Matthias Apsel
      1. 0
        Der-Dennis
        1. 0
          bubble
          1. 0
            Der-Dennis
        2. 0
          Matthias Apsel
        3. 0
          Matthias Apsel

Om nah hoo pez nyeetz, alle!

Wenn man für im Thema genanntes Spiel eine objektorientierte Umsetzung machen wollen würde, was wären dann sinnvolle Ansätze für die Wahl der Klassen?

Matthias

--
Der Unterschied zwischen Java und JavaScript ist größer als der zwischen Liter und Literaturpreis.

  1. Om nah hoo pez nyeetz, alle!

    Wenn man für im Thema genanntes Spiel eine objektorientierte Umsetzung machen wollen würde, was wären dann sinnvolle Ansätze für die Wahl der Klassen?

    Das Stichwort lautet "Multiple Dispatch", die Klassen an sich sind erstmal nicht so besonders wichtig. Siehe auch http://en.wikipedia.org/wiki/Multiple_dispatch. Das Beispiel dort mit den Raumschiffen und Asteroiden lässt sich gut auf die Karten übertragen.

    1. Das Stichwort lautet "Multiple Dispatch", die Klassen an sich sind erstmal nicht so besonders wichtig. Siehe auch http://en.wikipedia.org/wiki/Multiple_dispatch. Das Beispiel dort mit den Raumschiffen und Asteroiden lässt sich gut auf die Karten übertragen.

      Also ich habs jetzt auf englisch und deutsch gelesen und verstehe es immer noch nicht. Kann mir das jemand (mit Bienchen und Blümchen) erklären?

      Gruß
      Erklärbär fragendär
      T-Räx

      1. Das Stichwort lautet "Multiple Dispatch", die Klassen an sich sind erstmal nicht so besonders wichtig. Siehe auch http://en.wikipedia.org/wiki/Multiple_dispatch. Das Beispiel dort mit den Raumschiffen und Asteroiden lässt sich gut auf die Karten übertragen.

        Also ich habs jetzt auf englisch und deutsch gelesen und verstehe es immer noch nicht. Kann mir das jemand (mit Bienchen und Blümchen) erklären?

        Tja, das Design von Anwendungen ist eben nicht trivial. Hier unterscheidet sich der erfahrene Entwickler (ich bin keiner) vom indischen Standardprogrammierer. (SCNR)
        Spaß beiseite: es geht darum, dass eine Methode nicht mehr zwangsläufig zu einem einzelnen Objekt gehört, sondern dass es Methoden gibt, die auf zwei Objekten operieren und bei denen die Reihenfolge egal ist. Ob du "meinstring".equals("deinstring") oder meinObjekt.equals(deinObjekt) schreibst, beeinflusst (fachlich gesehen) das Ergebnis nicht. Daher ergibt es keinen Sinn, wenn der Methodenaufruf von equals für _ein_ Objekt definiert ist - er sollte generell auf zwei (oder ggf. sogar mehr) Objekten operieren - entscheidend ist dann nur die Anzahl und der Typ der Objekte.
        Damit vermeidet man z.B. Redundanzen und muss nachher nicht bei zwei verschiedenen Typen Code ändern, sondern nur noch an einer Stelle.
        Wenn die Sprache das nicht explizit ermöglicht, dann muss man es "nachbauen".

  2. Wenn man für im Thema genanntes Spiel eine objektorientierte Umsetzung machen wollen würde, was wären dann sinnvolle Ansätze für die Wahl der Klassen?

    Also Echse und Spock kenne ich nicht. Deshalb konzentriere ich mich mal auf die ersten drei.
    Ich würde eine Mutterkarte schaffen. Von der Leite ich ab:

    abstract class motherofallcards  
    {  
        protected $objBeat = null;  
        public function check( motherofallcards $objCheck )  
        {  
            //--- wenn die Objekte nicht verglichen werden können würde ich mit get_Class den Objekttypen vergleichen  
            if( $this->objBeat == $objCheck )  
            {  
                return -1;   //--- übergebenes Objekt ist stärker;  
            } else if( $objCheck == $this )  
            {  
                return 0;    //--- übergebenes Objekt entspricht aktuellem Objekt  
            }  
            return 1;  //--- aktuelles Objekt ist stärker  
        }  
    }  
      
    //--- Ableiten und benutzen  
    class stein extends motherofallcards  
    {  
        public function __construct()  
        {  
            $this->objBeat = new papier();  
        }  
    }
    

    Dann braucht es noch einen Controller (oder Router) der die Klassen initialisiert und entsprechend aufruft.
    Falls du es mit mehr als 3 Objekten machst, kannst du das einfache objbeat in ein Array umwandeln und dort alle Objekte reinschreiben die stärker sind.

    Gruß
    Kartenspieler
    T-Rex

    1. Hallo

      Wenn man für im Thema genanntes Spiel eine objektorientierte Umsetzung machen wollen würde, was wären dann sinnvolle Ansätze für die Wahl der Klassen?

      Also Echse und Spock kenne ich nicht.

      Schittebön

      Tschö, Auge

      --
      Verschiedene Glocken läuteten in der Stadt, und jede von ihnen vertrat eine ganz persönliche Meinung darüber, wann es Mitternacht war.
      Terry Pratchett, "Wachen! Wachen!"
      ie:{ fl:| br:> va:) ls:[ fo:) rl:( ss:| de:> js:| zu:}
      Veranstaltungsdatenbank Vdb 0.3
  3. Mahlzeit,

    Wenn man für im Thema genanntes Spiel eine objektorientierte Umsetzung machen wollen würde, was wären dann sinnvolle Ansätze für die Wahl der Klassen?

      
    class sheldon {}  
    
    

    Das reicht, denn diese Klasse muss perfekt sein :D

    --
    42
  4. Dazu reicht eine einzige Klasse mit dem Typ (Stein usw.) als Eigenschaft. Die Klasse muss nur noch wissen welcher Typ besser ist als welcher andere.
    Mit dem anlegen separater Klassen für jeden Typ hast du nichts gewonnen, das wird nur unübersichtlich.

    1. Om nah hoo pez nyeetz, Encoder!
      Om nah hoo pez nyeetz, T-Rex!

      Dazu reicht eine einzige Klasse mit dem Typ (Stein usw.) als Eigenschaft. Die Klasse muss nur noch wissen welcher Typ besser ist als welcher andere.

      Also so, wie man es auch prozedural machen würde: Die Procedur oder Funktion vergleicht die Kartenwerte.

      Fehlt noch eine Klasse Spieler. Deren Objekte können eine Karte wählen (durch Benutzereingabe oder zufällig), cheaten und kennen ihren Punktestand - richtig?

      Matthias

      --
      Der Unterschied zwischen Java und JavaScript ist größer als der zwischen Dia und Diana.

      1. Also so, wie man es auch prozedural machen würde: Die Procedur oder Funktion vergleicht die Kartenwerte.

        Ja. In OO heißt das dann Methode, da die Funktion zu einer Klasse gehört. Ist aber vom Verhalten her das selbe.

        Fehlt noch eine Klasse Spieler. Deren Objekte können eine Karte wählen (durch Benutzereingabe oder zufällig), cheaten und kennen ihren Punktestand - richtig?

        Ja.
        Cheaten?

        Hinter der Antwort wie du das genau designen solltest, steckt zunächst mal: willst du was praktisches machen das funktioniert und genügend sauber aber nicht unnötig komplex ist, oder möchtest du sozusagen ein Lehrbeispiel machen in dem alles durch und durch objektorientiert ist, auch wenn es für deine Situation nicht nötig ist und so schnell auch nicht sein wird.

        Du kannst schon auch für jeden Kartenwert (also Schere usw) eine eigene Karten-Klasse erstellen, von einer Basisklasse ableiten, dann im Konstruktur jeweils Eigenschaften setzen (Typ = Schere ...), Vergleichsmethoden für den Vergleich der aktuellen Kartenklasse mit einer anderen usw... Damit hättest du einen wunderbaren höchst objektorientierten Code laut Lehrbuch.
        Aber du machst dir eine wahnsinns Arbeit. Du hättest Klassen die sich in nur einer einzigen Eigenschaft unterscheiden. Viel Code, kaum Unterschied.

        Du könntest in jeder Klasse die Vergleiche der jeweiligen Klasse mit allen anderen einbauen, also Schere weiß ob sie im Vergleich mit allen anderen Karten gewinnt oder verliert, Stein weiß das ebenfalls für sich usw. Aber du reißt dadurch die Logik der Vergleiche auseinander. Die würde ich lieber in einer einzigen Funktion/Methode halten. Die kann in der Basisklasse stecken, oder wenns nur eine einzige Klasse bleibt, eben in dieser.

        1. Om nah hoo pez nyeetz, Encoder!

          willst du was praktisches machen das funktioniert und genügend sauber aber nicht unnötig komplex ist, oder möchtest du sozusagen ein Lehrbeispiel machen in dem alles durch und durch objektorientiert ist, auch wenn es für deine Situation nicht nötig ist und so schnell auch nicht sein wird.

          Ja. Beides. Ich will ein praktisches Beispiel haben, was meine Schüler wirklich selbst programmieren können. Und es soll tatsächlich objektorientiert sein. Ich will weg von diesen unsäglichen Beispielen (bzw. eigentlich auf diese aufbauen) Auto, Person, … die immer dafür herhalten müssen. Sie können das prozedural (Pascal) [ich hoffe, zumindest einige] und sollen halt im nächsten Jahr an die OOP herangeführt werden. Mit einer Doppelstunde in einem Schulhalbjahr kann das natürlich nur oberflächlich bleiben.

          Matthias

          --
          Der Unterschied zwischen Java und JavaScript ist größer als der zwischen Halle und Halleffekt.

          1. Sie können das prozedural (Pascal) [ich hoffe, zumindest einige] und sollen halt im nächsten Jahr an die OOP herangeführt werden. Mit einer Doppelstunde in einem Schulhalbjahr kann das natürlich nur oberflächlich bleiben.

            Ich bin kein Lehrer und weiß daher nicht, welche Freiheiten du beim Gestalten des Lehrplans genießt. Aber hast du schonmal daran gedacht statt an die OOP zuerst an die funktionale Programmierung heranzuführen? So wird das mittlerweile an immer mehr Universitäten gemacht und es hat einige Vorteile - denn der Weg von funktionaler Programmierung zu OOP ist weit einfacher als umgekehrt. Und funktionale Programmierung beinhaltet für die Schüler weniger "Overhead" und die Grundkonzepte sind wesentlich einfacher.

            1. Om nah hoo pez nyeetz, Whouzuo!

              Aber hast du schonmal daran gedacht statt an die OOP zuerst an die funktionale Programmierung heranzuführen?

              Egal wie, die Schüler müssen grundlegende Steuerstrukturen (Verzweigungen, Schleifen) kennenlernen. Das Funktionskonzept ist mit dabei.

              Dann erst geht es an die OOP.

              Matthias

              --
              Der Unterschied zwischen Java und JavaScript ist größer als der zwischen Oper und Operation.

              1. Om nah hoo pez nyeetz, Whouzuo!

                Aber hast du schonmal daran gedacht statt an die OOP zuerst an die funktionale Programmierung heranzuführen?

                Egal wie, die Schüler müssen grundlegende Steuerstrukturen (Verzweigungen, Schleifen) kennenlernen. Das Funktionskonzept ist mit dabei.

                Mit funktionaler Programmierung meine ich nicht (nur) die Nutzung von Funktionen. Da geht es schon um etwas mehr, z.B. dass Funktionen (andere) Funktionen zurückgeben können, Techniken wie Currying, Umgehen von Seiteneffekten usw.

                Mit (dr.)scheme z.B. können Schüler das gut lernen

        2. Om nah hoo pez nyeetz, Encoder!

          Cheaten?

          Betrügen. Nachgucken, was der Computer gewählt hat um die Gewinnchancen zu beeinflussen. Erstmal um immer mindestens ein Unentschieden zu erreichen. Dann: „Das ist jetzt natürlich zu auffällig!“ Also schummeln bei Bedarf. Da kann man in Gesprächen richtig gute Strategien erarbeiten.

          Matthias

          --
          Der Unterschied zwischen Java und JavaScript ist größer als der zwischen Klamm und Klammer.

  5. Ich muss Encoder ein wenig widersprechen. In der Praxis fangen die Projekte immer klein an. Bleiben sie klein hat Encoder vollkommen recht, dann bist du mit einer Funktion eventuell schneller. Werden sie größer wirst du irgendwann ein Problem haben. Zumal man beim entwickeln den Punkt eines Redesignes meistens verpasst.

    Deshalb würde ich auch bei kleinen Sachen sofort auf saubere Objekte legen. Wird es größer ist es total super einfach die entsprechenden Klassen zu erweitern.

    Hab meinen code auf 5 statt 3 Karten ausgelegt.

    abstract class motherofallcards  
    {  
        protected $arCheck = null;  
        public function check( motherofallcards $objCheck )  
        {  
            return $this->arCheck[ get_class($objCheck) ];  
        }  
    }  
      
    //--- Ableiten und benutzen  
    class stein extends motherofallcards  
    {  
        public function __construct()  
        {  
            $this->arCheck = array(  
                "stein" => 0,    //--- Unentschieden  
                "papier" => 1,   //--- Stärker  
                "echse" => 1,   //--- Stärker (weiß nicht ob das stimmt)  
                "schere" => -1,   //--- Schwächer  
                "spock" => -1   //--- Schwächer  
            );  
        }  
    }  
      
    //--- aufruf im Controller  
    $objKarteSpieler1 = new stein();  //--- Welche Klasse aufgerufen wird, wird im HTML (oder sonstwo) definiert  
    $objKarteSpieler2 = new papier();  
    $intResult = $objKarteSpieler1->check( $objKarteSpieler2 );  
    if( $intResult == 1 )  
    {  
       echo "Spieler 1 hat gewonnen und ist zudem total sexy und überhaupt super geil!";  
    } else if( $intResult == -1 ) {  
       echo "Spieler 2 hat gewonnen und ist zudem total sexy und überhaupt super geil!";  
    } else {  
       echo "Beide Spieler stinken!";  
    }  
    
    

    Gruß
    immer gewinnender
    T-Rex

    1. Hab meinen code auf 5 statt 3 Karten ausgelegt.

      [code lang=php]abstract class motherofallcards
      {
          protected $arCheck = null;
          public function check( motherofallcards $objCheck )
          {
              return $this->arCheck[ get_class($objCheck) ];
          }
      }

      //--- Ableiten und benutzen
      class stein extends motherofallcards
      {
          public function __construct()
          {
              $this->arCheck = array(
                  "stein" => 0,    //--- Unentschieden
                  "papier" => 1,   //--- Stärker
                  "echse" => 1,   //--- Stärker (weiß nicht ob das stimmt)
                  "schere" => -1,   //--- Schwächer
                  "spock" => -1   //--- Schwächer
              );
          }
      }

      Das ist schon besser, allerdings auch immernoch etwas ungünstig. Will man z.B. eine neue Karte hinzufügen, so muss man _jede_ andere Karte ändern. Man stelle sich das mal bei einem Kartenspiel mit 500 Karten vor...
      Zudem hat man Redundanz: in jeder Klasse steht ein Vergleichsarray für jede andere Karte. Dabei braucht man lediglich die Hälfte der Einträge, um eindeutig bestimmen zu können, welche Karte welche andere Karte schlägt.

      1. Will man z.B. eine neue Karte hinzufügen, so muss man _jede_ andere Karte ändern.

        Aus praktischen Gründen würde ich das auch in eine separate Methode auslagern, zum Beispiel in die Basisklasse. Oder man baut sich eine Vergleicher-Klasse, die nur für den Test zuständig ist.
        Die könnte dann wiederum von einer Methode innerhalb der Basisklasse für alle Steine usw. aufgerufen werden.

        1. Will man z.B. eine neue Karte hinzufügen, so muss man _jede_ andere Karte ändern.
          Aus praktischen Gründen würde ich das auch in eine separate Methode auslagern, zum Beispiel in die Basisklasse.

          Als statische Methode(n) in die Basisklasse, ja. Damit kommt man dem multiple dispatch schön näher. ;)
          Auch wenn sich mir noch nicht so ganz erschließt, warum die Basisklasse einer Karte das Vergleichen von Karten als Funktionalität beinhalten sollte.

          1. Als statische Methode(n) in die Basisklasse, ja. Damit kommt man dem multiple dispatch schön näher. ;)

            Die kann ja auch nicht-statisch sein. Wichtig wäre mir nur dass die Vergleiche nicht jeweils in den einzelnen Klassen ausprogrammiert werden müssen sondern an einer zentralen Stelle.

            Auch wenn sich mir noch nicht so ganz erschließt, warum die Basisklasse einer Karte das Vergleichen von Karten als Funktionalität beinhalten sollte.

            Die Basisklasse wäre ein Platz wo die Vergleichsmethode einmalig programmiert wird und alle anderen Klassen können drauf zugreifen. Man muss bei einer Erweiterung dann natürlich die Basisklasse mit anpacken. Andernfalls müsste man aber die spezielle Vergleichsmethode in jeder Klasse anpacken, das hat dann nichts mehr von einer einfachen Erweiterung.

            Dieses Beispiel ist als Lehrbeispiel schon nicht mehr ganz so simpel, von wegen es gibt eine neue Klasse die dann einfach mit ins bisherige System eingehängt wird ohne dass dieses von der neuen Klasse wissen muss. Hier gibts nämlich Abhängigkeiten untereinander.
            Ich würd das zuerst nur mit Schere, Stein, Papier machen. Spock und Echse kann man dann als Erweiterung reinbringen und daran zeigen wie die OO die Sache vereinfacht weil nur bestimmte Dinge angepasst werden müssen und weil man durch Ableitung auf bestehendes zugreifen kann.
            Da wäre es fürs Verständnis nicht ratsam, erst zu sagen "geht ganz einfach, hier kommt der Vorteil" und dann muss man aber alle anderen Klassen mit anpacken ;-)

            1. Als statische Methode(n) in die Basisklasse, ja. Damit kommt man dem multiple dispatch schön näher. ;)
              Die kann ja auch nicht-statisch sein.

              Nein, denn wie willst du eine abstrakte Karte instanziieren? Denn das musst du, wenn die Methode nicht statisch ist - es sei denn du willst sie auf den erbenden Karten aufrufen. Dann musst du aber ggf. eine konkrete Karte instanziieren, obwohl du die gar nicht brauchst. Klingt wenig sinnvoll oder?

              Dieses Beispiel ist als Lehrbeispiel schon nicht mehr ganz so simpel, von wegen es gibt eine neue Klasse die dann einfach mit ins bisherige System eingehängt wird ohne dass dieses von der neuen Klasse wissen muss. Hier gibts nämlich Abhängigkeiten untereinander.

              Naja, die anderen Klassen müssen nichts von dieser Klasse wissen. Auch nicht die Elternklasse. Nur die Methoden zum Vergleich (die eigentlich auch nicht in der Elternklasse stecken sollen - sie meinen Multiple Dispatch link) müssen erweitert werden.

              1. Das Beispiel ist anscheinend komplexer als man glauben möchte :-)

                Also ich stelle mir vor, die Methode sitzt in der Basisklasse, schaut sich den Typ der aktuellen Karte an ($this) und vergleicht diesen mit einer übergebenen Karte.
                Dazu kann die Methode nicht von einer Basisinstanz aufgerufen werden, das macht tatsächlich keinen Sinn. Aber jeder abgeleitete Instanz kann die Methode aufrufen.

                Dann musst du aber ggf. eine konkrete Karte instanziieren, obwohl du die gar nicht brauchst.

                Wenn man einen Vergleich der Eigenschaften an sich machen wollte ohne eine Karte zu haben, ja. Dann muss was anderes her. Aber am besten nicht gleich nochmal ein neues Konzept.

                Matthias darf jetzt nicht den Fehler machen, ein vollständig ausgefeiltes und in allen Ecken ausprogrammiertes Beispiel zu bringen, bei dem der wirkliche Vorteil von oo völlig untergeht. Da bleibt nämlich vor lauter "warum dieses, warum jenes" bei den Schülern nur ein Eindruck: es ist aufwendig, mehr Code, kompliziert und den Sinn hat vor lauter Details keiner verstanden.

                1. Om nah hoo pez nyeetz, Encoder!

                  Matthias darf jetzt nicht den Fehler machen, ein vollständig ausgefeiltes und in allen Ecken ausprogrammiertes Beispiel zu bringen, bei dem der wirkliche Vorteil von oo völlig untergeht.

                  Ich hab ja noch ein halbes Jahr Zeit.

                  Deshalb: Ich suche den sinnvollen Kompromiss.

                  Matthias

                  --
                  Der Unterschied zwischen Java und JavaScript ist größer als der zwischen Halle und Halleffekt.

                2. Das Beispiel ist anscheinend komplexer als man glauben möchte :-)

                  Also ich stelle mir vor, die Methode sitzt in der Basisklasse, schaut sich den Typ der aktuellen Karte an ($this) und vergleicht diesen mit einer übergebenen Karte.

                  Und wie entscheidet sie, welche Karte gewinnt? Wo findet sie diese Information?

                  Dann musst du aber ggf. eine konkrete Karte instanziieren, obwohl du die gar nicht brauchst.
                  Wenn man einen Vergleich der Eigenschaften an sich machen wollte ohne eine Karte zu haben, ja. Dann muss was anderes her. Aber am besten nicht gleich nochmal ein neues Konzept.

                  Doch, genau das. =)
                  Jedenfalls wenn man es sauber designen will. Das hat dann natürlich schon akademischen Anspruch und "lohnt" sich bei einem Miniprojekt oder einer Schulaufgabe nicht.

                  Matthias darf jetzt nicht den Fehler machen, ein vollständig ausgefeiltes und in allen Ecken ausprogrammiertes Beispiel zu bringen, bei dem der wirkliche Vorteil von oo völlig untergeht. Da bleibt nämlich vor lauter "warum dieses, warum jenes" bei den Schülern nur ein Eindruck: es ist aufwendig, mehr Code, kompliziert und den Sinn hat vor lauter Details keiner verstanden.

                  Ich wäre auch dagegen dieses Kartenbeispiel zu nehmen, denn es eignet sich nicht für das einfach Zeigen der Vorteile von OOP. Im Gegenteil, es demonstriert die Schwächen von OOP und die Tatsache, dass für manche Probleme OOP alleine nicht ausreichend ist.

                  1. Om nah hoo pez nyeetz, Whouzuo!

                    Ich wäre auch dagegen dieses Kartenbeispiel zu nehmen, denn es eignet sich nicht für das einfach Zeigen der Vorteile von OOP. Im Gegenteil, es demonstriert die Schwächen von OOP

                    Das ist ja auch schon mal was ;-)
                    Leider finde ich die Demonstration der Schwächen nicht so überzeugend, kannst du da etwas weiter ausholen?

                    Hättest du zudem ein Beispiel, das sich besser eignet?

                    Matthias

                    --
                    Der Unterschied zwischen Java und JavaScript ist größer als der zwischen Rap und Rapunzel.

                    1. Om nah hoo pez nyeetz, Whouzuo!

                      Ich wäre auch dagegen dieses Kartenbeispiel zu nehmen, denn es eignet sich nicht für das einfach Zeigen der Vorteile von OOP. Im Gegenteil, es demonstriert die Schwächen von OOP

                      Das ist ja auch schon mal was ;-)
                      Leider finde ich die Demonstration der Schwächen nicht so überzeugend, kannst du da etwas weiter ausholen?

                      Du wirst mir in PHP (ohne Nutzung einer Library, die multiple dispatch emuliert) keine Implementierung zeigen können, bei der du jeweils nur an einer Stelle im Code Änderungen vornehmen musst, um folgende Liste an fachlichen Änderungen durchzuführen:

                      1. Spiel um eine Karte erweitern (oder um eine Karte löschen)
                      2. Das Verhalten beim Vergleich von zwei Karten ändern
                      3. Eine Karte in einem anderen Zusammenhang verwenden (z.B. als Restaurantkarte) ohne ihre bisherigen Eigenschaften zu verändern oder zu löschen (lediglich ggf. zu ergänzen) (= keine Verletzung von Seperation of concerns)

                      Hättest du zudem ein Beispiel, das sich besser eignet?

                      Vielleicht eignen sich einfache Textspiele ganz gut, um soetwas zu zeigen. Z.B. mit Klassen wie Soldat, Panzer usw. da hat man dann auch wirkliche greifbare Vererbung. Aber du bist der Lehrer, du wirst es am besten wissen. Ich denke ich würde allerdings trotzdem mit funktionaler Programmierung anfangen; das ist viel besser greifbar und ohne soviel Overhead und blimblim drum herum. Denn was eine mathematische Funktion ist, das wissen die meisten wahrscheinlich schon.

                    2. Hättest du zudem ein Beispiel, das sich besser eignet?

                      Hier nochmal ein Link als Empfehlung für das Lernen von funktionaler Programmierung für Schüler:
                      http://www.mathematik.uni-muenchen.de/~schwicht/lectures/lehrer/ss00/fp.pdf

                      1. Om nah hoo pez nyeetz, Whouzuo!

                        Hier nochmal ein Link als Empfehlung für das Lernen von funktionaler Programmierung für Schüler:
                        http://www.mathematik.uni-muenchen.de/~schwicht/lectures/lehrer/ss00/fp.pdf

                        Danke für den Link. Rekursion ist imho die Obergrenze dessen, was man (im normalen Unterricht) machen kann. Das Vertauschen von zwei Elementen in einem Array überfordert viele Schüler schon.

                        Matthias

                        --
                        Der Unterschied zwischen Java und JavaScript ist größer als der zwischen Pier und Piercing.

      2. Om nah hoo pez nyeetz, Whouzuo!

        Dabei braucht man lediglich die Hälfte der Einträge, um eindeutig bestimmen zu können, welche Karte welche andere Karte schlägt.

        Ich würde aber aus Gründen der Übersichtlichkeit dennoch ein symmetrisches Array verwenden, auch wenn (bis auf die Hautptdiagonale - auf die sich auch verzichten lässt) alle Informationen doppelt vorkommen.

        Es ließe sich nämlich einfach schreiben check[h,c] (human bzw. computer) Im Array stehen 1,0,-1.

        Matthias

        --
        Der Unterschied zwischen Java und JavaScript ist größer als der zwischen Gut und Guttenberg.

        1. Om nah hoo pez nyeetz, Whouzuo!

          Dabei braucht man lediglich die Hälfte der Einträge, um eindeutig bestimmen zu können, welche Karte welche andere Karte schlägt.

          Ich würde aber aus Gründen der Übersichtlichkeit dennoch ein symmetrisches Array verwenden

          Wieso sollte das das ganze übersichtlicher machen?

          Es ließe sich nämlich einfach schreiben check[h,c] (human bzw. computer) Im Array stehen 1,0,-1.

          Dazu benötigt man nicht alle Einträge doppelt. Es reicht ja bei dem entsprechenden "fehlenden" Eintrag auf die Negierung des umgedrehten Eintrags zu verweisen.

          1. Om nah hoo pez nyeetz, Whouzuo!

            Wieso sollte das das ganze übersichtlicher machen?
            Dazu benötigt man nicht alle Einträge doppelt. Es reicht ja bei dem entsprechenden "fehlenden" Eintrag auf die Negierung des umgedrehten Eintrags zu verweisen.

            Das ist mir bewusst.

            {Var.1}  
              
            case check[h,c] of  
            	-1: {verloren}  
            	0:  {unentschieden}  
            	1:  {gewonnen}  
            end;  
              
            {Var.2}  
            	  
            gewinn := check[min(h,c),max(h,c)] * sgn(h-c);  
              
            case gewinn of  
            	-1: {verloren}  
            	0:  {unentschieden}  
            	1:  {gewonnen}  
            end;
            

            Man benötigt tatsächlich nur eine Zeile Quelltext mehr, die aber 3 Funktionsaufrufe enthält. In meinen Augen ist Variante 1 intuitiver, verständlicher und auch performanter und das trotz des höheren Speicherbedarfs für das Array. In dem Fall ist die Hauptdiagonale noch mit Nullen gefüllt.

            {Var.3}  
              
              
            if h <> c then  
            begin	  
            	gewinn := check[min(h,c),max(h,c)] * sgn(h-c);  
              
            	case gewinn of  
            		-1: {verloren}  
            		1:  {gewonnen}  
              
            	end;  
            end  
            else  
            	{unentschieden}
            

            Ohne die Hauptdiagonale im Array könnte es so aussehen.

            Matthias

            --
            Der Unterschied zwischen Java und JavaScript ist größer als der zwischen Klamm und Klammer.

            1. Om nah hoo pez nyeetz, Whouzuo!

              Wieso sollte das das ganze übersichtlicher machen?
              Dazu benötigt man nicht alle Einträge doppelt. Es reicht ja bei dem entsprechenden "fehlenden" Eintrag auf die Negierung des umgedrehten Eintrags zu verweisen.

              Das ist mir bewusst.

              {Var.1}

              case check[h,c] of
              -1: {verloren}
              0:  {unentschieden}
              1:  {gewonnen}
              end;

              {Var.2}

              gewinn := check[min(h,c),max(h,c)] * sgn(h-c);

              case gewinn of
              -1: {verloren}
              0:  {unentschieden}
              1:  {gewonnen}
              end;

              
              >   
              > Man benötigt tatsächlich nur eine Zeile Quelltext mehr, die aber 3 Funktionsaufrufe enthält.  
                
              Ich verstehe jetzt das zweite Beispiel nicht. Wieso hier objektorientiert nicht einfach karte1.compareTo(karte2) mittels Compare Interfaces oder aber gewinner = check(karte1, karte2)  
              ?  
              Der wirkliche check führt dann natürlich entsprechend die Funktion aus und negiert sie ggf. aber für den Aufrufer ist das eine blackbox, der soll davon gar nichts sehen.  
              Natürlich lässt sich das in PHP nicht umsetzen, weil PHP nicht nur schlecht OOP ist, sondern auch noch kein multiple dispatch kann.
              
              1. Om nah hoo pez nyeetz, Whouzuo!

                  
                
                > > {Var.2}  
                > > 	  
                > > gewinn := check[min(h,c),max(h,c)] * sgn(h-c);  
                > >   
                > > case gewinn of  
                > > 	-1: {verloren}  
                > > 	0:  {unentschieden}  
                > > 	1:  {gewonnen}  
                > > end;
                
                

                Man benötigt tatsächlich nur eine Zeile Quelltext mehr, die aber 3 Funktionsaufrufe enthält.

                Ich verstehe jetzt das zweite Beispiel nicht. Wieso hier objektorientiert nicht einfach karte1.compareTo(karte2) mittels Compare Interfaces oder aber gewinner = check(karte1, karte2)
                ?
                Der wirkliche check führt dann natürlich entsprechend die Funktion aus und negiert sie ggf. aber für den Aufrufer ist das eine blackbox, der soll davon gar nichts sehen.

                Das ist die Funktion, die genau das tut, wenn das Array reduziert ist. h und c sind IDs für karte1 und karte2. h steht in der Zeile, c in der Spalte

                Also mal so
                Das Array heißt check
                1=Stein, 2=Schere, 3=Papier

                ausführlich                reduziert mit Diagonale  
                   |  1  |  2  |  3           |  1  |  2  |  3  
                ---------------------      ---------------------  
                 1 |  0  |  1  | -1         1 |  0  |  1  | -1  
                 2 | -1  |  0  |  1         2 |     |  0  |  1  
                 3 |  1  |  -1 |  0         3 |     |     |  0
                

                Wenn das Array reduziert wird, gibt es nur noch Einträge check[h,c] mit h ≤ c.

                Deshalb also der Aufruf check[min(h,c),max(h,c)]. Ist jetzt aber h > c, muss ich den Wert, der im Array steht, mit -1 multiplizieren. sgn liefert das Vorzeichen einer Zahl also -1 für c-h falls h > c, 0 falls h = c und 1 falls h < c.

                Das heißt, die gewünschte Zahl ist check[min(h,c),max(h,c)] * sgn(c-h). Hier wäre ein Fehler in dem, was ich heute morgen mal eben schnell gepostet habe.

                Matthias

                --
                Der Unterschied zwischen Java und JavaScript ist größer als der zwischen Bus und Bussard.

                1. Om nah hoo pez nyeetz, Whouzuo!

                  {Var.2}

                  gewinn := check[min(h,c),max(h,c)] * sgn(h-c);

                  case gewinn of
                  -1: {verloren}
                  0:  {unentschieden}
                  1:  {gewonnen}
                  end;

                  
                  > > >   
                  > > > Man benötigt tatsächlich nur eine Zeile Quelltext mehr, die aber 3 Funktionsaufrufe enthält.  
                  > >   
                  > > Ich verstehe jetzt das zweite Beispiel nicht. Wieso hier objektorientiert nicht einfach karte1.compareTo(karte2) mittels Compare Interfaces oder aber gewinner = check(karte1, karte2)  
                  > > ?  
                  > > Der wirkliche check führt dann natürlich entsprechend die Funktion aus und negiert sie ggf. aber für den Aufrufer ist das eine blackbox, der soll davon gar nichts sehen.  
                  >   
                  > Das ist die Funktion, die genau das tut, wenn das Array reduziert ist. h und c sind IDs für karte1 und karte2. h steht in der Zeile, c in der Spalte  
                    
                  Okay, ich würde das auch nicht mit Arrays umsetzen. ;) PHP hat natürlich seine Grenzen.
                  
                  1. Om nah hoo pez nyeetz, Whouzuo!

                    Okay, ich würde das auch nicht mit Arrays umsetzen. ;) PHP hat natürlich seine Grenzen.

                    In dem Fall ist es Pascal.

                    Matthias

                    --
                    Der Unterschied zwischen Java und JavaScript ist größer als der zwischen Kai und Kaiser.

              2. Tach!

                Entschuldigung, wenn mein Einwurf hier nicht passen sollte, ich lese den Thread leider nur mit einem viertel Auge mit. Ich picke mir mal ein Detail heraus.

                Wieso hier objektorientiert nicht einfach karte1.compareTo(karte2) mittels Compare Interfaces ...

                Ist es wirklich günstig, dass das Objekt weiß, wie es sich mit anderen vergleichen kann? Muss eine Kuh wissen, wie sie sich selbst zu melken hat? Wenn man mal die "Und-Regel" ansetzt kommt bei einer Beschreibung der Klasse heraus: "... _und_ kann seine eigenen Instanzen miteinander vergleichen". Das heißt, das Objekt hat (mindestens) zwei Aufgaben und würde damit nicht dem Single-Responsibility-Prinzip entsprechen. Oder anders, mehr praktisch gedacht, je mehr Funktionalität hinzukommt, desto Monster wird es am Ende. Die Komplexität insgesamt bleibt erhalten und vergrößert sich sogar noch durch weitere Klassen, die aufgrund solcher Aufgabentrennungen entstehen. Aber dafür werden dann andere Dinge, wie zum Beispiel Unit-Tests wiederum überschaubarer, wenn nicht zu einer Monsterklasse moch Milionen von Testcases in einer Test-Klasse zu stehen kommen.

                dedlfix.

                1. Tach!

                  P.S.

                  ... "Und-Regel" ...

                  Diese besagt, wenn in der Beschreibung der Aufgabe einer Klasse ein "und" vorkommt, ist das ein Zeichen dafür, dass an dieser Stelle Funktionalität in eine eigene Klasse ausgelagert werden kann/sollte.

                  dedlfix.

                2. Tach!

                  Entschuldigung, wenn mein Einwurf hier nicht passen sollte, ich lese den Thread leider nur mit einem viertel Auge mit. Ich picke mir mal ein Detail heraus.

                  Wieso hier objektorientiert nicht einfach karte1.compareTo(karte2) mittels Compare Interfaces ...

                  Ist es wirklich günstig, dass das Objekt weiß, wie es sich mit anderen vergleichen kann?

                  Nein, eigentlich nicht. Es bleibt aber nichts anderes übrig, weil die Sprache nicht mehr hergibt. Genau wie z.B. Java. Und da ist compareTo wohl der beste Kompromiss.

      3. Das ist schon besser, allerdings auch immernoch etwas ungünstig. Will man z.B. eine neue Karte hinzufügen, so muss man _jede_ andere Karte ändern. Man stelle sich das mal bei einem Kartenspiel mit 500 Karten vor...

        Absolut richtig. Das es mehr Karten werden könnten habe ich nicht als Vorgabe angesehen. Deshalb habe ich mich für einen pragmatischen und doch OO-Ansatz entschieden.

        Zudem hat man Redundanz: in jeder Klasse steht ein Vergleichsarray für jede andere Karte. Dabei braucht man lediglich die Hälfte der Einträge, um eindeutig bestimmen zu können, welche Karte welche andere Karte schlägt.

        Man hat aber auch einen Vorteil.
        Mit einer theoretischen Methode (getVergleich) könnte man sich dieses Array zurück geben lassen und würde sofort ohne große Umrechnerrei sehen wie die Beziehung zu anderen Karten sind. Das könnte man für Infotäfelchen auf der Webseite benutzen.

        Was sagst du, ich rede meinen Vorschlag schön - okay du hast recht :(.

        Gruß
        Politikargumentübender
        T-Rex

    2. Nach gerechtfertigter Kritik gibts einen neuen Ansatz:

      abstract class motherofallcards  
      {  
          public function check( motherofallcards $objCheck )  
          {  
              //--- Der stärkere steht immer vorne  
              $arCheck = array(  
                  "stein" => "schere",  
                  "papier" => "stein",  
                  "schere" => "papier"  
              );  
        
              //--- übergebenes Objekt ist stärker  
              if( isset( $arCheck[ get_class($objCheck) ] ) &&  $arCheck[ get_class($objCheck) ] == get_class($this) )  
              {  
                  return -1;  
              } else if( isset( $arCheck[ get_class($this) ] ) &&  $arCheck[ get_class($this) ] == get_class($objCheck) )  
              {  
                  //--- übergebenes Objekt ist schwächer  
                  return 1;  
              }  
        
              //--- Unentschieden  
              if( get_class($this) == get_class($objCheck) )  
              {  
                  return 0;  
              }  
        
              //--- Karten nicht im Spiel implementiert  
              throw Exception();  
          }  
      }  
        
      //--- Ableiten und benutzen  
      class stein extends motherofallcards  
      {  
          //--- ziemlich leer :(  
      }
      

      Der Ansatz würde nicht funktionieren wenn irgendwann mal zwei unterschiedliche Karten zu einem unentschieden führen würden.
      Die Basisklasse muss um neue Karten erweitert werden.
      Jetzt ist alles in einer Funktion und Encoder hat recht, eine simple Funktion würde es jetzt auch tun *hmpf*.

      Neue Idee: Wenn man den Karten eine Wertigkeit geben könnte, dann könnte man mit dieser Wertigkeit vielleicht eine Logikaufbauen und das Array mit den Karten auflösen. Nehmen wir als Beispiel ein Normales Kartenspiel. Und ersetzten wir Bube, Dame, König und Aß durch 11,12,13,14. Dann hätte jede Karte eine Methode getWertigkeit(). Diese gibt die Wertigkeit zurück. Mit dieser kann man einfache Logiken aufbauen. Dann müsste es kein Array check in der Basisklasse geben und man könnte 500 Karten hinzuhängen ohne die Basisklasse anzuführen.

      Ganz andere Idee wäre ein Compiler. Diese Lösung ist etwas überdreht aber machbar.
      Ausgangssituation wäre wieder meine zweite Lösung mit dem Karten Array im Constructor (oder wo auch immer).

      $this->arCheck = array(  
          "stein" => 0,    //--- Unentschieden  
          "papier" => 1,   //--- Stärker  
          "echse" => 1,   //--- Stärker (weiß nicht ob das stimmt)  
          "schere" => -1,   //--- Schwächer  
          "spock" => -1   //--- Schwächer  
      );
      

      Hat man diese Klasse so erstellt und schmeißt den Compiler an, schneidet dieser das Array aus der Datei aus und baut sie in die Datei der Basisklasse ein. Heraus kommt die Lösung von oben mit dem Unterschied das man manuell nur die Ableitende Klasse anfassen muss. Ist diese einmal erstellt, wirft man den Compiler an. Dieser fügt das Karten Array in obiges Beispiel ein.
      Das hat aber nix mit OOP zu tun, sondern würde das "Problem" (falls es überhaupt eins ist), des hinzufügens etwas erleichtern.

      So jetzt hab ich keine Lust auf neue Ideen :p.

      Gruß
      ausgepumpter
      T-Rex

      1. Om nah hoo pez nyeetz, T-Rex!

        So jetzt hab ich keine Lust auf neue Ideen :p.

        In meinem Pascal-Programm habe ich folgende Arrays:

        wahl[1] := 'Stein';  
        wahl[2] := 'Schere';  
        ...  
          
        check[1,1] := 0; {Stein, Stein unentschieden}  
        check[2,1] := 1;  
        check[1,2] := -1;  
        check[2,2] := 0;
        

        und meine Auswertung sieht so aus:

        write (wahl[h]);  
        case check[h,c] of  
        	-1: write (' verliert gegen ');  
        	0:  write (' : ');  
        	1:  write (' schlägt ');  
        end;  
        writeln(wahl[c]);
        

        Wenn ich mir vernünftige Variablennamen ausdenken könnte, könnte auch (auf Kosten eines weiteren Arrays) ein Einzeiler draus werden.

        verb[0] := ' verliert gegen ';  
        verb[1] := ' : ';  
        verb[2] := ' schlägt ';  
          
        writeln (wahl[h], verb[check[h,c] + 1], wahl[c]);  
        
        

        Matthias

        --
        Der Unterschied zwischen Java und JavaScript ist größer als der zwischen Eis und Eisenbahn.

  6. Hallo Matthias,

    auch mal wieder was von mir. Auch wenn ich meistens nur lesend hier dabei bin. Aber Deinen Ansatz finde ich interessant.

    Dir geht es ja darum, Deinen _Schülern_ anhand Schere-Stein-Papier die OOP näherzubringen. Finde ich super. Ein guter Ansatz. Ganz wirst Du um das doofe Auto-Beispiel aber nicht rumkommen, so schlecht ist das nämlich meiner Meinung nach gar nicht (auch wenn's mich nervt; aber für mich das Ganze auch nicht mehr neu).

    Was mir aber beim Lesen der anderen Antworten aufgefallen ist: Da sind wirklich gute, ausgereifte Antworten dabei. Meiner Meinung nach gehen die aber an einem _Lehrbeispiel_ etwas vorbei. Es geht doch gar nicht in erster Linie um die Implementierung, sondern um das Verständnis, was OOP bedeutet. Dabei kann und sollte man auch Dinge machen, die man in der Praxis so nicht machen würde, wenn es denn dem Verständnis dient. Dass auch OOP nicht das Allheilmittel ist und man bei Änderungen häufig auch trotzdem mehrere Dateien anpacken muss - wie hier schon erwähnt wurde - ist doch gar nicht schlimm.

    So zurück zu den Autos :-) [Noch eine kurze Anmerkung: Folgendes ist natürlich noch keine fertige Lösung und soll nur in ein Gedankenanstoß sein.]

    Das Autobeispiel ist gut, weil jeder weiß, wie ein Auto aussieht. Im Sinne der OOP veranschaulicht es sehr schön, dass ein Objekt Eigenschaften und Methoden besitzt. Aber natürlich haben die Meisten hier, ebenso wie ich, keine Lust mehr auf _dieses_ Beispiel. Deswegen finde ich auch Deinen Ansatz spannend (könnten sich einige Lehrer mal ne Scheibe von abschneiden).

    Dann übertragen wir das "Auto-Beispiel" eben auf "Schnick-Schack-Schnuck".

    Als erstes müssen wir überhaupt verstehen, was das Spielprinizip hinter "Schere-Stein-Papier" ist:

    • Stein schlägt Schere
    • Schere schlägt Papier
    • Papier schlägt Stein

    Aber warum? Meiner Meinung nach wegen ihrer Eigenschaften:

    • Ein Stein ist "hart", er "zertrümmert" die Schere
    • Eine Schere ist "spitz", sie "schneidet" das Papier
    • Papier ist "flexibel", es "umwickelt" den Stein

    Wo ich gerade sehe, was ich bis jetzt geschrieben hab, sind wir der OOP ja schon näher, als ich vorher gedacht hätte...

    Also:

    • Stein, Schere und Papier sind Objekte

    • Ein Stein hat die Eigenschaft "hart"

    • Eine Schere hat die Eigenschaft "spitz" bzw. "scharf"

    • Papier hat die Eigenschaft "flexibel"

    Jedes besitzt eine "Angriffsvariante":
    Stein => "zertrümmern"
    Schere => "schneiden"
    Papier => "einwickeln"

    Das wäre dann wohl eine Methode (Name z.B. "Angriff", die allen Objekten gemein ist und die in eine abstrakte Oberklasse ausgelagert werden kann).

    Brauchen wir noch etwas, was die Korrelation herstellt:

    • Ein Objekt kann etwas "spitzes" "zertrümmern"
    • Ein Objekt kann etwas "flexibles" "schneiden"
    • Ein Objekt kann etwas "hartes" "einwickeln"

    Das wäre dann eine weitere, sozusagen eine "Konfigurations"-Klasse.

    Fehlt noch eine Klasse, die das auswertet. Sie könnte zwei "normale" Objekte (Schere, Stein, Papier) sowie ein "Konfigurations"-Objekt erhalten und dann die Prüfung durchführen.

    Ich "muss" jetzt leider Fußball gucken. Ich melde mich später nochmal. Nur noch zwei Dinge:
    1. Es ist nur ein Gedankenanstoß
    2. Sollte bspw. die "Prüfklasse" zu kompliziert werden (was ich aber nicht denke) spricht meiner Meinung nach auch nichts dagegen, wenn Du sie implementierst und den Schülern zu Verfügung stellst. Denn darum geht es ja gar nicht. An der Uni wird sowas übrigens auch ständig gemacht, weil die Lehrzeit sonst gar nicht ausreichen würde.

    Gruß und bis später,
    Dennis

    1. Hallo Matthias,

      so, Fußball ist vorbei und ich melde mich wie versprochen zurück.

      Nachdem ich mir gerade den Thread und auch meine Antwort nochmal durchgelesen habe, glaube ich, dass mein beschriebener Ansatz tatsächlich funktionieren könnte. Allerdings habe ich noch keine wirkliche Idee, wie man anhand dieses Beispiels Vererbung vernünftig darstellen/erklären könnte. Wahrscheinlich könnte man schon eher DI erklären, was aber bestimmt zu Anfang zu weit führen würde. Ich überlege aber weiter.

      Ich hab von Pascal überhaupt keine Ahnung. Noch nie was mit zu tun gehabt.

      Ich möchte aber, um die Idee etwas weiter zu spinnen, Whouzuos Beitrag aus einem anderen Post aufgreifen und versuchen, das Ganze ganz grob mittels PHP zu veranschaulichen. In diesem Beitrag steht:

      Du wirst mir in PHP (ohne Nutzung einer Library, die multiple dispatch emuliert) keine Implementierung zeigen können, bei der du jeweils nur an einer Stelle im Code Änderungen vornehmen musst, um folgende Liste an fachlichen Änderungen durchzuführen:

      1. Spiel um eine Karte erweitern (oder um eine Karte löschen)
      2. Das Verhalten beim Vergleich von zwei Karten ändern
      3. Eine Karte in einem anderen Zusammenhang verwenden (z.B. als Restaurantkarte) ohne ihre bisherigen Eigenschaften zu verändern oder zu löschen (lediglich ggf. zu ergänzen) (= keine Verletzung von Seperation of concerns)

      Ich gehe jetzt einfach mal davon aus, dass mit "nur an einer Stelle im Code Änderungen vornehmen" heißt, dass dies unabhängig von der neu zu erstellenden Klasse ist.

      Sollte ich mit Folgendem falsch liegen, korrigiert mich bitte (ich hab das nicht getestet, es geht nur um's Prinzip. Allerdings sollten sich, wenn ich richtig liege, die vorherigen Aussagen widerlegen lassen).

        
      <?php  
        
      abstract class SpielObjekt  
      {  
      	protected $eigenschaften = array();  
      	protected $angriffsvarianten = array();  
      	  
      	public function getEigenschaften()  
      	{  
      		return $this->eigenschaften;  
      	}  
      	  
      	public function getAngriffsvarianten()  
      	{  
      		return $this->angriffsvarianten;  
      	}  
      }  
        
      class Schere extends SpielObjekt  
      {  
      	protected $eigenschaften = array(  
      			'spitz');  
      	  
      	protected $angriffsvarianten = array(  
      			'schneiden');  
      }  
        
      class Stein extends SpielObjekt  
      {  
      	protected $eigenschaften = array(  
      			'hart');  
      	  
      	protected $angriffsvarianten = array(  
      			'zertrümmern');  
      }  
        
      class Papier extends SpielObjekt  
      {  
      	protected $eigenschaften = array(  
      			'flexibel');  
      	  
      	protected $angriffsvarianten = array(  
      			'einwickeln');  
      }  
        
      class Angriffszenarios  
      {  
      	protected $erfolgreich = array(  
      			'zertrümmern' => 'spitz',  
      			'schneiden' => 'flexibel',  
      			'einwickeln' => 'hart');  
      	  
      	public function getErfolgreich()  
      	{  
      		return $this->erfolgreich;  
      	}  
      }  
        
      class Prüfen  
      {  
      	public static function sagMirDenGewinner(SpielObjekt $a, Spielobjekt $b, Angriffscenarios $angriff)  
      	{  
      		$vergleich = $angriff->getErfolgreich();  
      		  
      		$ergebnisA = self::ergebnis($a->getAngriffsvarianten(), $b->getEigenschaften(), $vergleich);  
      		$ergebnisB = self::ergebnis($b->getAngriffsvarianten(), $a->getEigenschaften(), $vergleich);  
      		  
      		if ($ergebnisA > $ergebnisB) {  
      			return 1;  
      		} elseif ($ergebnisB > $ergebnisA) {  
      			return -1;  
      		}  
      		  
      		return 0;  
      	}  
      	  
      	protected static function ergebnis(array $a, array $b, array $vergleich)  
      	{  
      		$punkte = 0;  
      		  
      		foreach ($vergleich as $angriff => $eigenschaft) {  
      			if (in_array($angriff, $a) && in_array($eigenschaft, $b)) {  
      				$punkte++;  
      			}  
      		}  
      		  
      		return $punkte;  
      	}  
      }  
      
      

      Gruß, ich geh jetzt ins Bett
      (T-Rex, hast Du eigentlich gesehen, dass ich auf Deinen Wunsch hin immer noch etwas hinter "Gruß" schreibe?),
      Dennis

      1. Hallo Matthias,

        so, Fußball ist vorbei und ich melde mich wie versprochen zurück.

        Nachdem ich mir gerade den Thread und auch meine Antwort nochmal durchgelesen habe, glaube ich, dass mein beschriebener Ansatz tatsächlich funktionieren könnte. Allerdings habe ich noch keine wirkliche Idee, wie man anhand dieses Beispiels Vererbung vernünftig darstellen/erklären könnte. Wahrscheinlich könnte man schon eher DI erklären, was aber bestimmt zu Anfang zu weit führen würde. Ich überlege aber weiter.

        Ich hab von Pascal überhaupt keine Ahnung. Noch nie was mit zu tun gehabt.

        Ich möchte aber, um die Idee etwas weiter zu spinnen, Whouzuos Beitrag aus einem anderen Post aufgreifen und versuchen, das Ganze ganz grob mittels PHP zu veranschaulichen. In diesem Beitrag steht:

        Du wirst mir in PHP (ohne Nutzung einer Library, die multiple dispatch emuliert) keine Implementierung zeigen können, bei der du jeweils nur an einer Stelle im Code Änderungen vornehmen musst, um folgende Liste an fachlichen Änderungen durchzuführen:

        1. Spiel um eine Karte erweitern (oder um eine Karte löschen)
        2. Das Verhalten beim Vergleich von zwei Karten ändern
        3. Eine Karte in einem anderen Zusammenhang verwenden (z.B. als Restaurantkarte) ohne ihre bisherigen Eigenschaften zu verändern oder zu löschen (lediglich ggf. zu ergänzen) (= keine Verletzung von Seperation of concerns)

        Ich gehe jetzt einfach mal davon aus, dass mit "nur an einer Stelle im Code Änderungen vornehmen" heißt, dass dies unabhängig von der neu zu erstellenden Klasse ist.

        Sollte ich mit Folgendem falsch liegen, korrigiert mich bitte (ich hab das nicht getestet, es geht nur um's Prinzip. Allerdings sollten sich, wenn ich richtig liege, die vorherigen Aussagen widerlegen lassen).

        Guter Versuch, aber du hast erstens die Anforderungen verändert und insbesondere hast du folgendes verletzt: "ohne Nutzung einer Library, die multiple dispatch emuliert".
        Was du im Grunde getan hast ist ein einfaches "Scoringsystem" zu implementieren und einen eigenen Parser geschrieben, der Anhand festgelegter untypisierter Eigenschaften entsprechende Funktionalität ausführt (hier z.B. einfach Anhand von Vergleichen (bzw. dem Finden) von Strings in Arrays). Das geht natürlich und soetwas kann man in jeder Turing-vollständigen Sprache machen, es arbeitet aber um die Sprache herum, d.h. du hast quasi eine "Sprache in einer Sprache" implementiert. In Sprachen die multiple dispatch ermöglichen, ist dieses Drumherumarbeiten hingegen nicht nötig.

        Das ist etwas abstrakt, aber hier ein Beispiel, das es vielleicht etwas klarer macht, warum du "um die Sprache drumherum gearbeitet" hast: nehmen wir an jemand fügt eine neue Karte hinzu und ändert dein Array und ergänzt es um 'zertrümmern' => 'hart (oder irgendwas anderes)'. Was passiert? Es ändert sich das Verhalten von Karten, die überhaupt nicht betroffen sein sollten, es kann sogar zu logischen Fehlern führen (z.B. wenn für eine Karte gar kein Eintrag im Array ist). Wie würdest du dem begegnen? Richtig, du würdest Prüfungen machen, die dafür sorgen, dass jemand, der diese Funktionalität nutzt, nichts "logisch Falsches" eintragen kann, höchstens etwas "fachlich Falsches". Wenn du das vernünftig umsetzt, dann hast du nichts anderes getan als einen Parser zu schreiben, der die Struktur von deinem (immernoch recht einfachen) Array oder allgemeiner ausgedrückt deiner verwendeten Datenstruktur analysiert und validiert und dann die Eingaben in unterschiedliche Funktionalität umsetzt. Ups, das ist ja genau das, was ein Compiler macht.

        Dein Ansatz und Bauchgefühl ist somit völlig richtig! Du hast instinktiv gespürt, dass diese Sprache nicht mächtig genug ist, um deine Gedanken in ihr auszudrücken. Du hast daher die Sprache so erweitert, dass sie ausdrucksstärker wird. Das zeigt, dass du ein gutes Gespür dafür hast, ob du deine Gedanken 1:1 in eine Sprache übertragen kannst oder eben nicht. Vielen fällt es nichteinmal auf, dass sie um ihre wirklichen Gedanken "drumherum" arbeiten.

        Ein gutes Beispiel sind auch Arrays oder Listen. Nehmen wir eine Liste an Dateien, wobei jede Datei, die die Dateiendung "txt" hat, ausgegeben werden soll. Was sind deine Gedanken? "Nimm jede Datei aus der Liste, die keine Dateiendung hat und gib sie aus". In ausdrucksstarken Sprachen sieht das so aus:

        listeDerDateien.filter(datei -> datei.hatDateiEndung("txt)").each(datei -> datei.ausgeben())

        oder z.B. in Scala in kürzerer Form (wobei das _ sich immer auf ein Element der Liste bezieht):

        listeDerDateien.filter(_ hatDateiEndung "txt").forEach(_ ausgeben)

        Das spiegelt die Gedanken schon ziemlich gut wider. Wie oft sehe ich Programmierer, die folgendes schreiben (natürlich gibt es auch in PHP foreach o.ä.):

        for(int $i = 0; $i < size(listeDerDateien) - 1) {
           $aktuelleDatei = listeDerDateien[$i]
           if(aktuelleDatei.hatDateiEndung("txt")) {
              aktuelleDatei.ausgeben()
           }
        }

        Aber sind das wirklich die Gedanken, die man hat? Denkt man wirklich "mach eine Variable i und gib ihr den Wert 0, dann guck dir die Liste der Dateien an und hol dir die Anzahl deren Elemente, zieh davon 1 ab und solange Variable i kleiner als diese Anzahl ist tue... usw.
        Nicht wirklich oder? Eine Sprache sollte die eigenen Gedanken möglichst 1:1 widergeben, sodass Quellcode leicht verstanden und verändert werden kann. Die Aufgabe eines guten Entwicklers ist es dann, ein Problem richtig zu verstehen und es dann mithilfe der Sprache als Werkzeug zu formalisieren.

        1. Hallo Whouzuo,

          freut mich, dass Du geantwortet hast. Ein bisschen schade finde ich aber, dass Du eigentlich nicht mehr auf die eigentliche Ausgangsfrage (Matthias Frage im Zusammenhang mit dem, was ich geschrieben habe) eingegangen bist. Vielleicht holst Du das ja noch nach. Wäre doch schön, wenn wir mit Matthias zusammen eine schöne Lösung finden würden.

          Aber auch so hat mich interessiert, was zu antwortest. Deshalb hab ich Dich auch zitiert, weil ich Deine Aufgabenstellung gut fand. Ich hatte zuerst auch überlegt, ob ich Dich überhaupt zitieren sollte oder ob das am Ende blöd rüberkommt. Auch wenn ich nicht glaube, dass Du das so aufgefasst hast, hier nochmal explizit: Ich wollte nichts gegen Dich schreiben sondern etwas im Sinne Deiner Aufgabenstellung.

          Noch etwas zum Code: Wie ich zuvor schon erwähnt hatte, ging es mir keineswegs um ein konkretes oder vollständiges Beispiel, sondern nur um die Veranschaulichung meiner Idee. Und das im Sinne eines Lehrbeispiels, nicht in dem Sinne, wie man es in der Praxis wahrscheinlich umsetzen würde.

          In den Bereich begeben wir uns aber im Folgenden wieder. Nicht schlimm, ist auch interessant. Mich würde aber wie gesagt freuen, wenn wir in einem anderen Zweig des Threads wieder auf Matthias Frage eingehen.

          Guter Versuch, aber du hast erstens die Anforderungen verändert

          Ja, das habe ich. Und ganz so toll fand ich das auch nicht. Habe deswegen auch nochmal explizit nach Kritik gefragt. Warum ich die Anforderung verändert habe? Eigentlich einfach, ich kann mir einfach nicht vorstellen, wie Du bei Multiple Dispatch nur an einer Stelle Änderungen im Code vornehmen willst, um eine neue Klasse einzufügen (ich bin übrigens weder Informatiker noch sonst etwas in der Richtung und bei Multiple Dispatch weiß ich nur grob, um was es dabei geht). Meiner Meinung nach bräuchte es auch da Änderungen an mindestens zwei Stellen: Einmal musst Du eine Klasse (Karte) erstellen, auch wenn das bei Multiple Dispatch, wenn ich mich recht erinnere, nur ein mehr oder weniger leerer Rumpf ist (Änderung 1). Außerdem muss mindestens eine Methode geändert werden (Änderung 2). Und da ich gedacht habe, dass Du keine unlösbare Aufgabe stellst und - wenn auch nicht explizit - sagtest, dass sei mit Multiple Dispatch möglich, hab ich es auf eine Uneindeutigkeit geschoben und geändert.

          und insbesondere hast du folgendes verletzt: "ohne Nutzung einer Library, die multiple dispatch emuliert".

          Das musst Du mir bitte näher erklären, das verstehe ich nicht wirklich.

          Denn sollte stimmen, was ich glaube, was Du damit sagen möchtest, kann und will ich Dir zwar gar nicht widersprechen. Dann wäre diese Anforderung aber "für die Katz'". Klar, ich kann mir immer definieren, was eine "Library" ist. So können schon zwei Methoden, die eine bestimmte Aufgabe lösen sollen, eine Library sein. Und auch kann man sagen, dass "Vergleiche x mit y" eine Emulation von Multiple Dispatch ist. Sinnvoll ist das für mich aber nicht. Sprache, insbesondere allgemein verbreitete/verwendete, dient der Differenzierung verschiedener Sachverhalte. Alles andere ist nur verwirrend. Kläre mich also bitte auf. Ich lasse mich auch sehr gern eines Besseren belehren und nehme alles bisher gesagte zurück.

          Was du im Grunde getan hast ist ein einfaches "Scoringsystem" zu implementieren und einen eigenen Parser geschrieben, der Anhand festgelegter untypisierter Eigenschaften entsprechende Funktionalität ausführt (hier z.B. einfach Anhand von Vergleichen (bzw. dem Finden) von Strings in Arrays).

          Ja, wenn Du möchtest, darfst Du das so nennen, auch wenn ich persönlich das in diesem Kontext als verwirrend empfinden würde. Ich kriege es aber gerade ehrlich gesagt nicht hin, hier den Punkt zu finden, auf den Du hinaus möchtest.

          Das geht natürlich und soetwas kann man in jeder Turing-vollständigen Sprache machen, es arbeitet aber um die Sprache herum, d.h. du hast quasi eine "Sprache in einer Sprache" implementiert.

          Auch das darfst Du so nennen, wenn Du möchtest. Mit dieser Argumentation könnte man aber wirklich so ziemlich alles "Sprache in einer Sprache" nennen.

          In Sprachen die multiple dispatch ermöglichen, ist dieses Drumherumarbeiten hingegen nicht nötig.

          Auch hier bitte ich um eine Erklärung, weil nun folgendes Beispiel mir überhaupt nicht erklären kann, was Du damit ausdrücken möchtest. Im Gegenteil erscheint es mir so, dass Du gerade genau gegen Multiple Dispatch argumentierst (siehe dazu auch weiter unten, auch wenn Du dort bereits auf "ausdrucksstarke Sprachen" zu sprechen gekommen bist; da das alles aber fließend ineinander übergeht, vermute ich, es steht in Zusammenhang zueinander).

          Das ist etwas abstrakt, aber hier ein Beispiel, das es vielleicht etwas klarer macht, warum du "um die Sprache drumherum gearbeitet" hast: nehmen wir an jemand fügt eine neue Karte hinzu und ändert dein Array und ergänzt es um 'zertrümmern' => 'hart (oder irgendwas anderes)'. Was passiert? Es ändert sich das Verhalten von Karten, die überhaupt nicht betroffen sein sollten, es kann sogar zu logischen Fehlern führen (z.B. wenn für eine Karte gar kein Eintrag im Array ist).

          Nein, kann es meiner Meinung nach nicht. Erstens ging es um ein Lehrbeispiel und zweitens um etwas realitätsnahes, was verständlich rüberkommt.

          • Die einzelnen Spielobjekte sollen realitätsnahe Eigenschaften bekommen. Diese gelten auch außerhalb des Spiels bzw. in einem anderen Kontext (Ein "Stein" ist "hart", egal ob im Spiel oder in der Realität; ja, ich weiß, es gibt auch "weiche" "Steine", das spielt aber doch für diese ganz abstrakte Veranschaulichung keine Rolle).
          • Die einzelnen Spielobjekte sollen realitätsnahe "Angriffe" erhalten, welche auch außerhalb dieses Kontextes gelten (Ja, eine Schere muss auch nicht spitz sein...)
          • Die Korrelationen sollen "echte physikalische Gegebenheiten" oder so was in der Art erfassen und diese auch außerhalb des Spiels beibehalten (Ja, etwas "flexibles" wickelt nicht zwingend etwas "hartes" ein...)

          Von der technischen Seite her: Wenn für eine Karte kein Eintrag im Array ist, beeinflusst das die Funktionsweise keineswegs, wenn ich im Beispiel keinen Fehler gemacht habe. Findet man im Korrelations-Array den entsprechenden "Angriff" nicht, so führt er schlicht und einfach ins Leere. Gibt es dort eine bestimmte Eigenschaft nicht, so führt ein möglicher Angriff ins Leere. Und das ist so gewollt, wie zuvor hoffentlich verständlich beschrieben.

          Wie würdest du dem begegnen? Richtig, du würdest Prüfungen machen, die dafür sorgen, dass jemand, der diese Funktionalität nutzt, nichts "logisch Falsches" eintragen kann, höchstens etwas "fachlich Falsches". Wenn du das vernünftig umsetzt, dann hast du nichts anderes getan als einen Parser zu schreiben, der die Struktur von deinem (immernoch recht einfachen) Array oder allgemeiner ausgedrückt deiner verwendeten Datenstruktur analysiert und validiert und dann die Eingaben in unterschiedliche Funktionalität umsetzt. Ups, das ist ja genau das, was ein Compiler macht.

          Nö, für solch ein Szenario (Lehrbeispiel) braucht man keine weiteren Prüfungen. Wahrscheinlich nicht mal in einem praxisnahen Beispiel. Blödsinn und Fehler kann man immer machen, da hilft auch die beste Prüfung nichts. Wenn da einer reinschreibt "Fußgänger überfährt Auto" soll er das machen. Kann ich eh nicht ändern. Ist seine Entscheidung. Und wenn jemand der Prüffunktion was übergeben möchte, was nicht von "Spielobjekt" abgeleitet wurde, gibt's halt nen Fehler. Wie vorher schon gesagt: Es sei Dir unbenommen, dass "Parser", "Compiler" oder wie-auch-immer zu nennen. Sinnvoll ist das meiner Meinung nach nicht.

          Dein Ansatz und Bauchgefühl ist somit völlig richtig! Du hast instinktiv gespürt, dass diese Sprache nicht mächtig genug ist, um deine Gedanken in ihr auszudrücken. Du hast daher die Sprache so erweitert, dass sie ausdrucksstärker wird. Das zeigt, dass du ein gutes Gespür dafür hast, ob du deine Gedanken 1:1 in eine Sprache übertragen kannst oder eben nicht. Vielen fällt es nichteinmal auf, dass sie um ihre wirklichen Gedanken "drumherum" arbeiten.

          Spätestens jetzt habe ich wirklich etwas den Faden verloren, was Du mir sagen möchtest (ich komme jetzt zu dem, auf was ich voher schon verwiesen hatte). Eindeutig widersprechen kann ich Dir, dass "diese Sprache nicht mächtig genug ist, um deine Gedanken in ihr auszudrücken". Wie man - so hoffe ich jedenfalls - erkennen kann, ist diese Sprache mächtig genug, dass ich meine Intention mit ihrer Hilfe widerspiegeln konnte. Zumindest Matthias und Du scheinen ja meine Idee nachvollzogen und verstanden zu haben. Sozusagen q.e.d. Dass ich die "Sprache so erweitert [habe], dass sie ausdrucksstärker wird", bezweifle ich nicht. Das ist aber die Voraussetzung für Programmierung. Man muss mit der Sprache arbeiten. Programmiersprachen, (die nicht nur einzig und allein eine Aufgabe erfüllen,) müssen abstrakt sein. Und jeden Algorithmus, den man schreibt, kann man als "Sprache in der Sprache" oder "Erweiterung" oder "Library" bezeichnen. Aber was hat das mit "drumherum" zu tun? Ist es nicht viel mehr "mit"?

          Außerdem (auch darauf kommst Du gleich noch zu sprechen): Wie ist das bei Multiple Dispatch (habe gerade extra nochmal bei Wikipedia reingeschaut)? Ist es intuitiv und entspricht es weitgehend Deinen Gedanken, dass Du eine abstrakte Klassendefinition, eine abstrakte Methodendefinition und eine "kryptische" Methodenimplmentierung angeben kannst, um "blaues Auto" zu sagen? Ich vermute eher nicht. Und das ist auch gar nicht schlimm, es ist eine Konvention. Ich glaube auch, dass Multiple Dispatch in einigen Bereichen sinnvoll ist, aber halt nicht immer und überall. Es gibt nun mal nur"optimale" (im Sinne von: zufriedenstellende) Lösungen, keine "perfekten" (im Sinne von: besser geht's nicht"). Hast Du natürlich auch nicht behauptet, ich musste es aber gerade loswerden ;-)

          [Dein Lob habe ich übrigens erkannt und dankend angenommen, auch wenn es nicht so anhört. Kann ich übrigens nur zurück geben, Du hast mich richtig zum Nach- und Überdenken angeregt.]

          Ein gutes Beispiel sind auch Arrays oder Listen. [Beispiel entfernt]

          Aber sind das wirklich die Gedanken, die man hat? Denkt man wirklich "mach eine Variable i und gib ihr den Wert 0, dann guck dir die Liste der Dateien an und hol dir die Anzahl deren Elemente, zieh davon 1 ab und solange Variable i kleiner als diese Anzahl ist tue... usw. Nicht wirklich oder?

          Nein, natürlich nicht. Da gebe ich Dir recht. Aber wo ist das Problem? So funktioniert jede Sprache nun einmal, sonst wäre es keine Sprache. Eine Sprache ist einfach eine Konvention, um anderen "Objekten" (im Normalfall: anderen Menschen) seine Gedanken verständlich zu machen. Ich muss auch bei der "natürlichen Sprache" Umwege in Kauf nehmen und mit der Sprache arbeiten. Alles andere würde nicht funktionieren, keiner würde mich verstehen oder neue Gedanken könnten nicht gedacht werden.

          Eine Sprache sollte die eigenen Gedanken möglichst 1:1 widergeben, sodass Quellcode leicht verstanden und verändert werden kann. Die Aufgabe eines guten Entwicklers ist es dann, ein Problem richtig zu verstehen und es dann mithilfe der Sprache als Werkzeug zu formalisieren.

          Da stimme ich Dir zu 100% zu. Ich glaube sowieso, dass wir beide ähnliches meinen und doch etwas anderes sagen bzw. schreiben. Ein Fehler unserer Sprache ;-) Aber einfach nur "Ente" zu sagen bringt uns auch nicht weiter.

          Entschuldigt bitte, dass das jetzt so lang geworden ist. Kürzer hat es unsere Sprache aber leider nicht zugelassen. Ich freue mich jedenfalls auf Deine Antwort. Noch schöner fände ich allerdings, wenn wir statt technische oder sprachliche Dinge zu diskutieren, Matthias gemeinsam mit allen anderen bei seinem Vorhaben unterstützen.

          Gruß, der T-Rex hat noch nix zu meiner zweiten Grußzeile gesagt, Dennis

          Ps: Wo ich meinen Text gerade nochmal in der Vorschau gelesen habe: Manches ist nicht ganz so toll formuliert, Whouzuo, es ist aber nichts auch nur im Entferntesten böse gemeint!

          1. Hallo Whouzuo,

            freut mich, dass Du geantwortet hast. Ein bisschen schade finde ich aber, dass Du eigentlich nicht mehr auf die eigentliche Ausgangsfrage (Matthias Frage im Zusammenhang mit dem, was ich geschrieben habe) eingegangen bist. Vielleicht holst Du das ja noch nach. Wäre doch schön, wenn wir mit Matthias zusammen eine schöne Lösung finden würden.

            Worauf denn jetzt genau? Ich bin der Meinung, dass man gar nicht mit OOP anfangen sollte, sondern mit funktionaler Programmierung. Denn OOP ist viel viel schwieriger - wir empfinden es nur nicht so, weil wir den Lernprozess schon hinter uns haben.

            Aber auch so hat mich interessiert, was zu antwortest. Deshalb hab ich Dich auch zitiert, weil ich Deine Aufgabenstellung gut fand. Ich hatte zuerst auch überlegt, ob ich Dich überhaupt zitieren sollte oder ob das am Ende blöd rüberkommt.

            Nein wieso denn? Das ist doch ein spannendes und interessantes Thema. Ich habe das jetzt auch nicht so empfunden als würdest du "gegen" mich schreiben. Falls das aufgrund meines Schreibstils (bei diesem Thema werde ich einfach emotional ;)) so herübergekommen ist, dann sei hiermit gesagt, dass es nicht so gemeint war.

            Guter Versuch, aber du hast erstens die Anforderungen verändert

            Ja, das habe ich. Und ganz so toll fand ich das auch nicht. Habe deswegen auch nochmal explizit nach Kritik gefragt. Warum ich die Anforderung verändert habe? Eigentlich einfach, ich kann mir einfach nicht vorstellen, wie Du bei Multiple Dispatch nur an _einer_ Stelle Änderungen im Code vornehmen willst, um eine neue Klasse einzufügen (ich bin übrigens weder Informatiker noch sonst etwas in der Richtung und bei Multiple Dispatch weiß ich nur grob, um was es dabei geht).

            Dem Hinzufügen einer neuen Klasse _muss_ natürlich auch das Hinzufügen einer Bewertung an einer anderen Stelle folgen - außer es wird sonst ein default Verhalten vorgegeben. Das hast du ja auch erkannt.

            Meiner Meinung nach bräuchte es auch da Änderungen an mindestens zwei Stellen: Einmal musst Du eine Klasse (Karte) erstellen, auch wenn das bei Multiple Dispatch, wenn ich mich recht erinnere, nur ein mehr oder weniger leerer Rumpf ist (Änderung 1).

            Der Punkt ist, dass der Typ der Karte selbst für die späteren Entscheidungen herangezogen wird und man somit mit der Definition der Klasse bereits fertig ist.

            und insbesondere hast du folgendes verletzt: "ohne Nutzung einer Library, die multiple dispatch emuliert".

            Das musst Du mir bitte näher erklären, das verstehe ich nicht wirklich.

            Denn sollte stimmen, was ich glaube, was Du damit sagen möchtest, kann und will ich Dir zwar gar nicht widersprechen. Dann wäre diese Anforderung aber "für die Katz'". Klar, ich kann mir immer definieren, was eine "Library" ist. So können schon zwei Methoden, die eine bestimmte Aufgabe lösen sollen, eine Library sein. Und auch kann man sagen, dass "Vergleiche x mit y" eine Emulation von Multiple Dispatch ist.

            Genau so ist es. In einer entsprechend ausdrucksstarken Sprache musst du solche Vergleich nicht mehr "händisch" anstellen, das übernimmt das Typsystem der Sprache vollständig für dich. Mit allen Vorteilen, z.B. automatischer Prüfung, ob jeder Typ definiert wurde, ob du Subtypen an den entsprechenden Stellen verwenden darfst und viel viel mehr. Es ist absolut kein Vergleich von Strings, Ints oder Ähnlichem notwendig, weil das der Compiler für dich tut - und wie er das intern tut, das interessiert dich nicht (solange es funktioniert).

            Was du im Grunde getan hast ist ein einfaches "Scoringsystem" zu implementieren und einen eigenen Parser geschrieben, der Anhand festgelegter untypisierter Eigenschaften entsprechende Funktionalität ausführt (hier z.B. einfach Anhand von Vergleichen (bzw. dem Finden) von Strings in Arrays).

            Ja, wenn Du möchtest, darfst Du das so nennen, auch wenn ich persönlich das in diesem Kontext als verwirrend empfinden würde. Ich kriege es aber gerade ehrlich gesagt nicht hin, hier den Punkt zu finden, auf den Du hinaus möchtest.

            Verwirrend? Ein Parser ist jetzt nichts besonders Kompliziertes. Und dass ich es nicht schaffe dir näher zu bringen, was ich meine, das stimmt wohl. ;)

            Das geht natürlich und soetwas kann man in jeder Turing-vollständigen Sprache machen, es arbeitet aber um die Sprache herum, d.h. du hast quasi eine "Sprache in einer Sprache" implementiert.

            Auch das darfst Du so nennen, wenn Du möchtest. Mit dieser Argumentation könnte man aber wirklich so ziemlich alles "Sprache in einer Sprache" nennen.

            Nein. Man kann das leicht prüfen. Du willst ein Programm schreiben, das eine bestimmte Funktionalität beinhaltet und tust das in einer Sprache mit "mittlerer" Ausdrucksstärke, die aber völlig ausreicht, um dein Programm umzusetzen, ohne dass du um die Sprache drumherum arbeiten musst. Wenn du das Programm jetzt in eine Sprache mit höherer Ausdrucksstärke portierst, musst du konzeptionell nichts ändern, du kannst deinen Code quasi bis auf eine andere Syntax 1:1 übernehmen. Willst du das Programm hingegen in eine Sprache niedrigerer Ausdrucksstärke portieren, musst du plötzlich das Design deines Programms umändern. Z.B. mehr oder andere Methoden verwenden, neue Variablen einführen etc.
            Stell dir mal vor eine Sprache unterstützt keine Funktionen mit Rückgabewerten, sondern nur Prozeduren. Dann musst du erstmal eine Variable vor dem Aufruf der Prozedur erstellen, in der Prozedur diese Variable verändern und dann dafür sorgen, dass alle anderen Variablen nicht verändert wurden. Du bildest damit also einen Teil des Compilers, der Funktionen unterstützt, in der Sprache nach.

            Lies auch mal das: http://gafter.blogspot.de/2007/03/on-expressive-power-of-programming.html

            Wenn dir das immernoch alles zu schwammig ist oder unklar ist, melde dich auf Stack Overflow. ;)

            In Sprachen die multiple dispatch ermöglichen, ist dieses Drumherumarbeiten hingegen nicht nötig.

            Auch hier bitte ich um eine Erklärung, weil nun folgendes Beispiel _mir_ überhaupt nicht erklären kann, was Du damit ausdrücken möchtest.
            Im Gegenteil erscheint es mir so, dass Du gerade genau gegen Multiple Dispatch argumentierst (siehe dazu auch weiter unten, auch wenn Du dort bereits auf "ausdrucksstarke Sprachen" zu sprechen gekommen bist; da das alles aber fließend ineinander übergeht, vermute ich, es steht in Zusammenhang zueinander).

            Das ist etwas abstrakt, aber hier ein Beispiel, das es vielleicht etwas klarer macht, warum du "um die Sprache drumherum gearbeitet" hast: nehmen wir an jemand fügt eine neue Karte hinzu und ändert dein Array und ergänzt es um 'zertrümmern' => 'hart (oder irgendwas anderes)'. Was passiert? Es ändert sich das Verhalten von Karten, die überhaupt nicht betroffen sein sollten, es kann sogar zu logischen Fehlern führen (z.B. wenn für eine Karte gar kein Eintrag im Array ist).

            Nein, kann es meiner Meinung nach nicht.

            Es kann nicht zu logischen Fehlern führen, wenn man den von mir oben genannten Eintrag macht? Was denn sonst?

            Erstens ging es um ein Lehrbeispiel und zweitens um etwas realitätsnahes, was verständlich rüberkommt.

            • Die einzelnen Spielobjekte sollen realitätsnahe Eigenschaften bekommen. Diese gelten auch außerhalb des Spiels bzw. in einem anderen Kontext (Ein "Stein" ist "hart", egal ob im Spiel oder in der Realität; ja, ich weiß, es gibt auch "weiche" "Steine", das spielt aber doch für diese ganz abstrakte Veranschaulichung keine Rolle).
            • Die einzelnen Spielobjekte sollen realitätsnahe "Angriffe" erhalten, welche auch außerhalb dieses Kontextes gelten (Ja, eine Schere muss auch nicht spitz sein...)
            • Die Korrelationen sollen "echte physikalische Gegebenheiten" oder so was in der Art erfassen und diese auch außerhalb des Spiels beibehalten (Ja, etwas "flexibles" wickelt nicht zwingend etwas "hartes" ein...)

            Stimmt ja alles, hat aber was hat das jetzt mit dem Array zu tun, durch das die Bewertung gemacht wird? Das bleibt ja wie es ist.

            Von der technischen Seite her: Wenn für eine Karte kein Eintrag im Array ist, beeinflusst das die Funktionsweise keineswegs, wenn ich im Beispiel keinen Fehler gemacht habe. Findet man im Korrelations-Array den entsprechenden "Angriff" nicht, so führt er schlicht und einfach ins Leere.

            Es wird dann entsprechend eine 0 zurückgegeben, d.h. der Default-Case für nicht vorhandene Karten wäre, dass keine gewinnt. Solange das so gewollt ist, okay. Aber der Compiler schützt dich hier nicht davor, den Fehler zu machen, dass du eben eine Kombination vergisst. Du musst dich selbst darum kümmern und dir entweder darüber im Klaren sein, dass der defaultcase = 0 okay ist oder du musst abprüfen, ob keine Kombination vergessen wurde und dann eine Exception schmeißen.
            Was in deinem kleinen Beispiel noch kein Problem sein mag, führt bei größeren Spielen sehr schnell zu einem Problem. Dort will man in Regel explizit vom Compiler darauf hingewiesen werden, dass z.B. der Aufruf von ergebnis(karte1, karte2) nicht erlaubt ist, weil diese Funktion (noch) nicht existiert (wenn kein Defaultfall angegeben ist).
            Was passiert, wenn in deinem Array zweimal der gleiche Eintrag drin ist? Es wird eine 2 zurückgegeben, deine Abfrage ob ergebis = 1 oder ergebnis = -1 trifft nicht zu und es wird ausgegeben, dass es keinen Gewinner gab. Das war mit Sicherheit nicht das, was du gewollt hast oder? In einer entsprechenden Programmiersprache hättest du gar kein "if" schreiben müssen - der Fehler hätte dir nie passieren können. Den können dann natürlich stattdessen die Entwickler der Sprache machen, aber das ist nicht mehr dein Toast. ;)

            Wie würdest du dem begegnen? Richtig, du würdest Prüfungen machen, die dafür sorgen, dass jemand, der diese Funktionalität nutzt, nichts "logisch Falsches" eintragen kann, höchstens etwas "fachlich Falsches". Wenn du das vernünftig umsetzt, dann hast du nichts anderes getan als einen Parser zu schreiben, der die Struktur von deinem (immernoch recht einfachen) Array oder allgemeiner ausgedrückt deiner verwendeten Datenstruktur analysiert und validiert und dann die Eingaben in unterschiedliche Funktionalität umsetzt. Ups, das ist ja genau das, was ein Compiler macht.

            Nö, für solch ein Szenario (Lehrbeispiel) braucht man keine weiteren Prüfungen.

            Natürlich! Für ein Lehrbeispiel braucht man auch keine "high sophisticated" Programmiersprache. Das ändert aber nichts daran, dass dieses Problem mit PHP nicht ausgedrückt werden kann, ohne die von mir aufgestellten Bedingungen zu verletzten. PHP ist nicht ausdrucksstark genug.

            Wahrscheinlich nicht mal in einem praxisnahen Beispiel. Blödsinn und Fehler kann man immer machen, da hilft auch die beste Prüfung nichts. Wenn da einer reinschreibt "Fußgänger überfährt Auto" soll er das machen.

            Das ist aber ein fachlicher Fehler, kein logischer. Dagegen kann dich natürlich nichts schützen - aber das ist auch nicht die Aufgabe des Compilers. Der soll dich vor logischen Fehlern schützen.

            1. Hallo Whouzuo,

              auch wenn es jetzt wieder um Implementierung geht und unabhängig von dem, was ich vorher geschrieben hab (und was natürlich weiterhin gilt): Kannst Du mir folgendes bitte nochmal in anderen Worten erklären? Ich bin zwar grad müde und geh jetzt ins Bett, hab aber das Gefühl, ich steh grad völlig auf dem Schlauch.

              Was passiert, wenn in deinem Array zweimal der gleiche Eintrag drin ist? Es wird eine 2 zurückgegeben, deine Abfrage ob ergebis = 1 oder ergebnis = -1 trifft nicht zu und es wird ausgegeben, dass es keinen Gewinner gab. Das war mit Sicherheit nicht das, was du gewollt hast oder? In einer entsprechenden Programmiersprache hättest du gar kein "if" schreiben müssen - der Fehler hätte dir nie passieren können. Den können dann natürlich stattdessen die Entwickler der Sprache machen, aber das ist nicht mehr dein Toast. ;)

              Danke, Gruß und gute Nacht,
              jetzt geht's ab in die T-Rex-Höhlen-Heia (ohne T-Rex),
              Dennis

          2. Kann ich eh nicht ändern. Ist seine Entscheidung. Und wenn jemand der Prüffunktion was übergeben möchte, was nicht von "Spielobjekt" abgeleitet wurde, gibt's halt nen Fehler.

            Ja, nur kosten diese Art der Fehler ziemlich viel Geld - je größer, komplexer und integrierter Software wird, desto mehr Fehler dieser Art treten auf. Statische Typisierung ist nicht umsonst entwickelt worden. (und wird es immernoch)

            Wie vorher schon gesagt: Es sei Dir unbenommen, dass "Parser", "Compiler" oder wie-auch-immer zu nennen. Sinnvoll ist das _meiner_ Meinung nach nicht.

            Deine Meinung in allen Ehren - die Entwicklung der neueren Programmiersprachen und z.B. auch die Änderungen in Java 8 zeigen, dass es sehr wohl sinnvoll ist. Alles geht in diese Richtung.

            Spätestens jetzt habe ich wirklich etwas den Faden verloren, was Du mir sagen möchtest (ich komme jetzt zu dem, auf was ich voher schon verwiesen hatte).
            Eindeutig widersprechen kann ich Dir, dass "diese Sprache nicht mächtig genug ist, um deine Gedanken in ihr auszudrücken". Wie man - so hoffe ich jedenfalls - erkennen kann, ist diese Sprache mächtig genug, dass ich meine Intention mit ihrer Hilfe widerspiegeln konnte.

            Ja, indem du einen Mini-Interpreter geschrieben hast. ;)
            Wie gesagt, nach deiner Definition kann man auch jede Intention mit Assembler ausdrücken oder nicht?

            Zumindest Matthias und Du scheinen ja meine Idee nachvollzogen und verstanden zu haben. Sozusagen q.e.d.

            Ich möchte aber, dass auch du es tust. Du musst ja nicht mit mir übereinstimmen, aber meine Ansichten nachvollziehen zu können - das wäre doch schön.

            Dass ich die "Sprache so erweitert [habe], dass sie ausdrucksstärker wird", bezweifle ich nicht. Das ist aber die Voraussetzung für Programmierung.

            Nein, das ist nicht richtig. Natürlich muss man mit der Sprache arbeiten, aber man muss sie nicht zwangsläufig ausdrücksstärker machen.

            Außerdem (auch darauf kommst Du gleich noch zu sprechen): Wie ist das bei Multiple Dispatch (habe gerade extra nochmal bei Wikipedia reingeschaut)? Ist es intuitiv und entspricht es weitgehend Deinen Gedanken, dass Du eine abstrakte Klassendefinition, eine abstrakte Methodendefinition und eine "kryptische" Methodenimplmentierung angeben kannst, um "blaues Auto" zu sagen?

            Intuitiv nicht, nein. Aber ich kann damit meinem Gedanken ohne drumherum ausdrücken. Alles was halbwegs komplex ist, ist nicht mehr intuitiv - solange bis es intuitiv wird. ;)

            Ein gutes Beispiel sind auch Arrays oder Listen. [Beispiel entfernt]

            Aber sind das wirklich die Gedanken, die man hat? Denkt man wirklich "mach eine Variable i und gib ihr den Wert 0, dann guck dir die Liste der Dateien an und hol dir die Anzahl deren Elemente, zieh davon 1 ab und solange Variable i kleiner als diese Anzahl ist tue... usw.
            Nicht wirklich oder?

            Nein, natürlich nicht. Da gebe ich Dir recht. Aber wo ist das Problem? So funktioniert _jede_ Sprache nun einmal, sonst wäre es keine Sprache.

            Das war ja nur ein Beispiel. Und das ist durchaus ein Problem, denn je einfacher verständlich der geschriebene Quellcode, desto besser. Übrigens ist auch eine Schleife mit Variablen inhaltlich etwas anderes als die foreach Lösung. Ja wirklich: beide Varianten KÖNNEN sich gleich verhalten, müssen es aber nicht. Erkennst du, warum?

            Eine Sprache ist einfach eine Konvention, um anderen "Objekten" (im Normalfall: anderen Menschen) seine Gedanken verständlich zu machen. Ich muss auch bei der "natürlichen Sprache" Umwege in Kauf nehmen und mit der Sprache arbeiten. Alles andere würde nicht funktionieren, keiner würde mich verstehen oder neue Gedanken könnten nicht gedacht werden.

            Gruß,
            der T-Rex hat noch nix zu meiner zweiten Grußzeile gesagt,
            Dennis

            Ps: Wo ich meinen Text gerade nochmal in der Vorschau gelesen habe: Manches ist nicht ganz so toll formuliert, Whouzuo, es ist aber nichts auch nur im Entferntesten böse gemeint!

            Kein Problem, besonders Freitags nach der Arbeit. ;)

            1. Hallo Whouzuo,

              ich möchte mich gerne selbst zitieren:

              Ich glaube sowieso, dass wir beide Ähnliches meinen und doch etwas anderes sagen bzw. schreiben. Ein Fehler unserer Sprache ;-)

              Ich hab mir den Link von Dir zwar noch nicht angesehen, denke aber, der wird an dieser Aussage nicht viel ändern. Ich schau ihn mir morgen aber aus reinem Interesse an. (Schrecklich: Seit ich nicht mehr in die Schule muss, lerne ich gerne!)

              Ansonsten möchte ich auf Deine Beiträge gar nicht näher eingehen. Außer Du möchtest, dass ich zu irgendeinem bestimmten Punkt, der Dir wichtig ist, "Stellung beziehe". Das mache ich gerne, aber - und da wiederhole ich mich - glaube ich nicht, dass das jemanden weiterbringt. Ich denke, Du und ich wollen (von Nuancen abgesehen, die wir aber sicher auch nicht durch ein paar Forum-Posts ändern können) in die gleiche Richtung.

              Größtenteils - aber nicht in der Gänze - stimme ich Dir natürlich zu! Und ich behaupte, ich hab Dich jetzt auf jeden Fall verstanden.

              Auf jeden Fall kann ich Dir sagen, dass Du durch Deine letzten beiden Beiträge für mich "viel Licht ins Dunkel" gebracht hast, was Du meintest. Und das für mich viel verständlicher als vorher rübergebracht hast. Kompliment, nach meinem so nem langen Beitrag. Und das freut mich (vorallem, weil ich beim Großteil, den ich geschrieben hab, nicht völlig an Dir vorbeigeredet hab - und umgekehrt).

              Danke! Und mich würde wirklich freuen, wenn wir jetzt zusammen (und natürlich mit den anderen) Matthias unterstützen. Für diese "Abseits-Gespräche" haben wir ja nachher noch genug Zeit. Matthias hat ja nur noch nen halbes Jahr :-)

              Gruß, Dennis

    2. Om nah hoo pez nyeetz, Der-Dennis!

      Vielen Dank, deine Beiträge sind ungeheuer hilfreich.

      Dir geht es ja darum, Deinen _Schülern_ anhand Schere-Stein-Papier die OOP näherzubringen.

      Und Schüler darf man dabei nicht mit Studenten verwechseln, es gibt nämlich welche, die machen das aus Bequemlichkeit, weil sie meinen, das sei der leichteste Weg und es gibt auch leistungsschwächere Schüler, die dann mit einem ausreichend auch tatsächlich zufrieden sind.

      Und man darf auch einen Lehrer nicht mit einem Informatiker oder Programmierer verwechseln. Es kann nicht um mehr als die grundlegensten Grundlagen gehen. Und dabei bemühe ich mich, keinen Blödsinn zu verzapfen, teils aus Gründen der didaktischen Reduktion, teils aus Gründen des eigenen Unwissens. (Von Currying habe ich zum Beispiel vorher noch nie was gehört)

      Finde ich super. Ein guter Ansatz.

      Danke.

      Ganz wirst Du um das doofe Auto-Beispiel aber nicht rumkommen, so schlecht ist das nämlich meiner Meinung nach gar nicht (auch wenn's mich nervt; aber für mich das Ganze auch nicht mehr neu).

      Das ist klar.

      Das Autobeispiel ist gut, weil jeder weiß, wie ein Auto aussieht. Im Sinne der OOP veranschaulicht es sehr schön, dass ein Objekt Eigenschaften und Methoden besitzt. Aber natürlich haben die Meisten hier, ebenso wie ich, keine Lust mehr auf _dieses_ Beispiel. Deswegen finde ich auch Deinen Ansatz spannend (könnten sich einige Lehrer mal ne Scheibe von abschneiden).

      Vor allem, weil ich ein halbes Jahr vorher mit der Vorbereitung anfange ;-)

      Ich wünsche mir, dass ich mit diesem Beispiel mehr Schüler erreiche, als lediglich mit getAnzahlDerTüren und Volltanken.

      Ich bin dabei, mit Schülern der 10. Klassen (von denen einige dann im nächsten Jahr hoffentlich in meinem Info-Kurs sitzen), das SSP prozedural in Pascal zu entwickeln. Dabei geht es hauptsächlich um Steuerstrukturen.

      Einige Schüler scheitern schon daran,

      Gib die Temperatur ein!  
      25  
      Du darfst kurze Hosen anziehen
      

      umzusetzen.

      Und die machen das nicht mit Absicht.

      Nochmals vielen Dank für deinen Beitrag. Vielleicht ergeben sich ja jetzt noch Diskussionen, die für mich hilfreich sind. Dabei will ich die Beiträge von T-Rex, Encoder oder Whouzuo in keiner Weise herabwürdigen.

      Matthias

      --
      Der Unterschied zwischen Java und JavaScript ist größer als der zwischen Boot und Bootes.

      1. Hallo Matthias,

        Vielen Dank, deine Beiträge sind ungeheuer hilfreich.

        das freut mich ehrlich. Kann ich mich vielleicht mal wenigstens ein bisschen revanchieren und nicht immer nur "schmarotzen". Obwohl ich alles, was ich durch SelfHTML und insbesondere durch das Forum bereits gelernt habe, sicherlich nicht vollständig zurückgeben kann. Finde es eh erstaunlich, was man hier wirklich jeden Tag neues lernen kann.

        Dir geht es ja darum, Deinen _Schülern_ anhand Schere-Stein-Papier die OOP näherzubringen.

        Und Schüler darf man dabei nicht mit Studenten verwechseln, es gibt nämlich welche, die machen das aus Bequemlichkeit, weil sie meinen, das sei der leichteste Weg und es gibt auch leistungsschwächere Schüler, die dann mit einem ausreichend auch tatsächlich zufrieden sind.

        Ich weiß, dass es das gibt. Aber ist das im Schulalltag wirklich so verbreitet? Ich meine, Info in ner 10. Klasse ist doch sicher kein Pflichtfach, oder?

        Und man darf auch einen Lehrer nicht mit einem Informatiker oder Programmierer verwechseln. Es kann nicht um mehr als die grundlegensten Grundlagen gehen. Und dabei bemühe ich mich, keinen Blödsinn zu verzapfen, teils aus Gründen der didaktischen Reduktion, teils aus Gründen des eigenen Unwissens. (Von Currying habe ich zum Beispiel vorher noch nie was gehört)

        Ich auch noch nie. Wo wir wieder beim Punkt von oben wären :-)

        Und weil Du es erwähnst: Dann bin ich ab jetzt auch Lehrer. Mich darf man auch nicht mit solchen Experten verwechseln :-)

        Vor allem, weil ich ein halbes Jahr vorher mit der Vorbereitung anfange ;-)

        Stimmt, das hattest Du ja vorher schon geschrieben. Hab ich überlesen. Also: Heft raus! Gibt mindestens ein Fleiß-Sternchen ;-)
        (Nein, im Ernst: Finde ich wirklich ne tolle Sache, dass Du das machst. Es gibt zwar wirklich ein paar Lehrer, die das so wie Du machen; leider gibt es aber auch hier, wie in jeder anderen Berufsgruppe auch, viel zu viele, die das überhaupt nicht juckt. Nett ausgedrückt.)

        Ich wünsche mir, dass ich mit diesem Beispiel mehr Schüler erreiche, als lediglich mit getAnzahlDerTüren und Volltanken.

        Dann hoffe ich einfach, dass Deine Schüler erkennen, was Du so alles machst und das wertzuschätzen wissen. Ich drücke Dir die Daumen, dass Dein Wunsch in Erfüllung geht.

        [...] Und die machen das nicht mit Absicht.

        Finde ich immer traurig. Allgemein, nicht wegen Deinem konkreten Beispiel. Naja, die Hoffnung stirbt zuletzt und Du arbeitest ja daran, dass es nicht dabei bleibt.

        Vielleicht ergeben sich ja jetzt noch Diskussionen, die für mich hilfreich sind.

        Fände ich auf jeden Fall echt gut und interessant. Vor allem so Punkte wie z.B., wie Du so was wie Vererbung an diesem Beispiel vernünftig erklären könntest. Oder hast Du schon eine Idee? Ich hab nämlich überhaupt keine. "Bimsstein extends Stein" finde ich einfach "zu billig". Und wir wären wieder beim Auto...

        Dabei will ich die Beiträge von T-Rex, Encoder oder Whouzuo in keiner Weise herabwürdigen.

        Da Du das gerade nochmal extra erwähnst: Ich hoffe, ich habe mit meinem Beitrag zum Ausdruck gebracht, dass ich genau das ebenfalls nicht machen wollte. Nur für den Fall, jemand hat mich hier missverstanden.

        Dennis

        1. Ich bin nur gespannter Mitleser im Thread, da ich leider nichts beisteuern kann.

          Fände ich auf jeden Fall echt gut und interessant. Vor allem so Punkte wie z.B., wie Du so was wie Vererbung an diesem Beispiel vernünftig erklären könntest. Oder hast Du schon eine Idee? Ich hab nämlich überhaupt keine. "Bimsstein extends Stein" finde ich einfach "zu billig". Und wir wären wieder beim Auto...

          An dem Beispiel wird das mMn. schwer, da das Spektrum des Wissens/Interesses zu groß ist, aber hier mal eine hoffentlich hilfreiche Anregung:

          Ich kann mich partout nicht mehr daran erinnern ob es bei mir in der 9. oder in der 10. Klasse war, jedenfalls hatten wir sowohl in Info als auch in Biologie das Thema Vererbung.
          So kam es dazu dass eine abstrakte Klasse Mensch deklariert wurde mit ein paar Eigenschaften und ein paar Funktionen (welche meist nur die Eigenschaften in einem kurzen Satz ausgegeben haben). Jedenfalls wusste unser Info-Lehrer, dass wir in Bio auch Vererbung hatten, so hat er in der Vater-Klasse im Konstruktor halt eine Augenfarbe definiert und der erbenden Klasse (=das Kind) halt die Augenfarbe überschrieben (Stichwort rezessive und dominante Vererbung).

          IMHO ist die Hälfte der Vererbung schon gegessen, wenn man in Bio schon so weit war, so dass man eigentlich fast nur noch die programmiersprachlichen Differenzen erklären muss, da es ja vom Prinzip her das gleiche ist.

          MfG
          bubble

          PS: Ich muss zwar gleich los aber das will ich auch noch schnell einwerfen bezüglich Vererbung in Bezug auf Funktionen: eine Amöbe bewegt sich komplett anders als Vogel vorwärts. Oder ein Auto *SCNR*

          --
          If "god" had intended us to drink beer, he would have given us stomachs. - David Daye
          1. Hallo bubble,

            Ich bin nur gespannter Mitleser im Thread, da ich leider nichts beisteuern kann.

            Lügner!

            Gruß, Dennis

        2. Om nah hoo pez nyeetz, Der-Dennis!

          Und Schüler darf man dabei nicht mit Studenten verwechseln, es gibt nämlich welche, die machen das aus Bequemlichkeit, weil sie meinen, das sei der leichteste Weg und es gibt auch leistungsschwächere Schüler, die dann mit einem ausreichend auch tatsächlich zufrieden sind.

          Ich weiß, dass es das gibt. Aber ist das im Schulalltag wirklich so verbreitet? Ich meine, Info in ner 10. Klasse ist doch sicher kein Pflichtfach, oder?

          Es sitzt immer™ die gesamte Bandbreite im Unterricht.

          Matthias

          --
          Der Unterschied zwischen Java und JavaScript ist größer als der zwischen Fan und Fango.

        3. Om nah hoo pez nyeetz, Der-Dennis!

          Fände ich auf jeden Fall echt gut und interessant. Vor allem so Punkte wie z.B., wie Du so was wie Vererbung an diesem Beispiel vernünftig erklären könntest. Oder hast Du schon eine Idee? Ich hab nämlich überhaupt keine. "Bimsstein extends Stein" finde ich einfach "zu billig". Und wir wären wieder beim Auto...

          Du kannst ja mal das überaus aussagekräftige Kerncuriculum lesen ;-) Da ist der Rahmenplan (Erprobungsfassung 2002!) schon etwas aussagekräftiger.

          Für die Vererbung habe noch keine Idee. Eine Verdeutlichung ist ja schon das Ableiten der Schere von SpielObject.

          Matthias

          --
          Der Unterschied zwischen Java und JavaScript ist größer als der zwischen Mars und Marschflugkörper.