{"id":9753,"date":"2017-08-13T10:12:53","date_gmt":"2017-08-13T08:12:53","guid":{"rendered":"https:\/\/www.herr-rau.de\/wordpress\/?p=9753"},"modified":"2023-06-12T09:14:38","modified_gmt":"2023-06-12T07:14:38","slug":"eine-kleine-programmieraufgabe","status":"publish","type":"post","link":"https:\/\/www.herr-rau.de\/wordpress\/2017\/08\/eine-kleine-programmieraufgabe.htm","title":{"rendered":"Eine kleine Programmieraufgabe&#8230;"},"content":{"rendered":"<div style='text-align:right;'><small>(<a href='https:\/\/www.herr-rau.de\/wordpress\/2017\/08\/eine-kleine-programmieraufgabe.htm#comments'>11 Kommentare.<\/a>)<\/small> <\/div>\n<p>&#8230;die sich als aufw\u00e4ndiger und lehrreicher herausgestellt hat, als ich dachte.<\/p>\n\n\n\n<p>Es begann damit, dass ein Kollege mir von dem Computerspiel erz\u00e4hlte, das ihn gerade besch\u00e4ftigte: Als Schiffbr\u00fcchiger auf einer Insel sammelt man unter anderem Gegenst\u00e4nde ein und erntet Pflanzen, jagt Tiere und arbeitet mit Werkzeugen. Zum Beispiel kann man mit einem Messer und einer Kokosnuss man Trinkwasser erzeugen (wobei die Kokosnuss verbraucht wird), und mit einem Schwein und einem Messer erzeugt man Haut und Fleisch, und aus der Haut kann man Leder machen, und aus dem Leder Riemen, und so weiter.<\/p>\n\n\n\n<p>Ha, dachte ich mir, das ist nett, das sieht objektorientiert aus, das k\u00f6nnte ich doch auch mal mit Sch\u00fclern machen. Erster Gedanke:<\/p>\n\n\n\n<figure class=\"wp-block-image\"><img loading=\"lazy\" decoding=\"async\" width=\"521\" height=\"237\" src=\"https:\/\/www.herr-rau.de\/wordpress\/archiv\/inselspiel.png\" alt=\"Klassendiagramm\" class=\"wp-image-9767\" srcset=\"https:\/\/www.herr-rau.de\/wordpress\/archiv\/inselspiel.png 521w, https:\/\/www.herr-rau.de\/wordpress\/archiv\/inselspiel-150x68.png 150w, https:\/\/www.herr-rau.de\/wordpress\/archiv\/inselspiel-300x136.png 300w\" sizes=\"auto, (max-width: 521px) 100vw, 521px\" \/><\/figure>\n\n\n\n<p>Das Messer kriegt folgende Methoden:<\/p>\n\n\n\n<ol class=\"wp-block-list\">\n<li>eine Methode <code>anwendenAuf(Kokosnuss)<\/code><\/li>\n\n\n\n<li>eine Methode <code>anwendenAuf(Schwein)<\/code><\/li>\n\n\n\n<li>eine Methode <code>anwendenAuf(Spielobjekt)<\/code><br>(eventuell verzichtbar, da ererbt, aber siehe weiter unten)<\/li>\n<\/ol>\n\n\n\n<p>Diese drei Methoden hei\u00dfen zwar alle gleich, sind aber trotzdem verschiedene Methoden und machen verschiedene Sachen &#8211; dieses Konzept hei\u00dft <em>overloading.<\/em> &#8211; Ein anderes Konzept ist das des <em>overriding<\/em>, wenn eine Unterklasse die gleichnamige Methode der Oberklasse \u00fcberschreibt. Das ist der Fall, wenn Methode (3) die ererbte gleichnamige Methode \u00fcberschreibt. Siehe weiter unten. &#8211; Wenn man die Methode <code>anwendenAuf<\/code> mit einem Kokosnuss-Objekt als Parameter aufruft, wird Methode (1) ausgew\u00e4hlt und ausgef\u00fchrt, wenn man sie mit einem Schwein-Objekt aufruft, wird (2) ausgef\u00fchrt, wenn man sie mit irgendeinem anderen Spielobjekt-Objekt als Parameter aufruft, wird die Methode (3) ausgef\u00fchrt.<\/p>\n\n\n\n<p>Dann w\u00fcrde jede Sch\u00fclerin, jeder Sch\u00fcler eine eigene Klasse erzeugen (Messer, Kokosnuss, Hammer, Feuerstein, Zange&#8230;.) und w\u00fcrde f\u00fcr jede interessante Interaktion mit einem anderen Objekttyp eine eigene <code>anwendenAuf<\/code>-Methode schreiben &#8211; und die Catch-all-Methode f\u00fcr die restlichen Objekttypen \u00fcbernehmen. Das f\u00e4nde ich ordentlich.<\/p>\n\n\n\n<p>Das funktioniert auch wie gedacht, aber leider nur erst einmal, und dann doch nicht: In der Regel wird man eine Liste oder ein Array von Spielobjekten haben, und der Spieler w\u00e4hlt eins davon aus und wendet sein Messer darauf an. Und dann wird automatisch und stets die Methode (3) aufgerufen, auch wenn sich hinter dem Spielobjekt eine Kokosnuss verbirgt. Will hei\u00dfen, wenn ich folgenden Code ausf\u00fchre:<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">Spielobjekt o = new Kokosnuss();\nKokosnuss k = new Kokosnuss();\nSpielobjekt m = new Messer();\nm.anwendenAuf(o);\nm.anwendenAuf(k);<\/pre>\n\n\n\n<p>Dann wird bei <code>m.anwendenAuf(o)<\/code> die Methode (3) aufgerufen, und nur bei <code>m.anwendenAuf(k)<\/code> wird die Methode (1). Denn wenn die ausf\u00fchrbaren Java-Klassen erzeugt werden, also beim Compilieren, also \u00dcbersetzen des Quellcodes, dann gilt: Die Kokosnuss o ist vom Typ Spielobjekt, basta. Das hei\u00dft <em>static binding.<\/em> Bei diesem \u00dcberstzen wird dann festgelegt, dass bei <code>m.anwendenAuf(o)<\/code> eben die Methode (3) ausgef\u00fchrt wird. Und das geschieht dann auch, wenn das Programm tats\u00e4chlich ausgef\u00fchrt wird.<\/p>\n\n\n\n<p>Zwar hat beim <em>Ausf\u00fchren<\/em> des Programms das Objekt o dann den Typ Kokosnuss, wie man herausfinden kann durch einen Aufruf von <code>System.out.println( o.getClass() )<\/code>. Aber das bringt nichts mehr, da ist die Wahl bereits getroffen. Etwas anders ist es bei ererbten und \u00fcberschriebenen Methoden. Hier noch einmal die Zeilen von oben:<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">Spielobjekt o = new Kokosnuss();\nSpielobjekt m = new Messer();\nm.anwendenAuf(o);<\/pre>\n\n\n\n<p>In der letzten Zeile wird immer noch die Methode (3) <code>anwendenAuf(Spielobjekt)<\/code> aufgerufen. Aber es ist die Methode, die in der Klasse Messer definiert ist, und nicht die gleichnamige in der \u00fcbergeordneten Klasse Spielobjekt. Das ist das <em>overriding<\/em> von vorhin, und dabei wird erst zur Laufzeit entschieden, also wenn das Programm tats\u00e4chlich l\u00e4uft, welche der beiden Methoden aufgerufen wird. Die Maschine schaut zur Laufzeit, von welchem Typ m <em>wirklich<\/em> ist (n\u00e4mlich Messer, und nicht Spielobjekt), und w\u00e4hlt dann die entsprechende Methode. Das hei\u00dft dann <em>dynamic binding.<\/em><\/p>\n\n\n\n<p>Kurz gesagt:<\/p>\n\n\n\n<ol class=\"wp-block-list\">\n<li>Wenn ein Objekt eine ererbte Methode mit einer eigenen \u00fcberschreibt, wird stets letztere ausgef\u00fchrt. In der Unterklasse entscheidet man also selber, ob die ererbte Methode benutzt werden soll oder ob es stattdessen eine eigene Methode geben wird.<\/li>\n\n\n\n<li>Wenn ein Objekt allerdings als Parameter einer Methode \u00fcbergeben wird, hat die Klasse, die diese Methode zur Verf\u00fcgung stellt, keine Auswahlm\u00f6glichkeit und kann den Objekttyp des Parameters nicht als Auswahlkriterium heranziehen. Der wird vorher festgelegt auf das, was da steht, egal welche Klasse wirklich dahinter steckt.<\/li>\n<\/ol>\n\n\n\n<p>Fazit: Die Klasse Messer braucht nur eine einzige Methode <code>anwendenAuf(Spielobjekt)<\/code>. Man muss das ganze so machen:<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">void anwendenAuf(Spielobjekt o) {\n  if (o instanceof Kokosnuss) {\n    \/\/ ...\n  }\n  else if (o instanceof Schwein) {\n    \/\/ ...\n  }\n  else {\n    \/\/ ...\n  }\n}<\/pre>\n\n\n\n<p>Ich finde das ein bisschen weniger \u00fcbersichtlich, als f\u00fcr jedes Objekt eine eigene Methode zu haben. Au\u00dferdem st\u00f6rt mich der instanceof-Operator. Mit dem kann man herausfinden, ob ein Objekt zu einer bestimmten Klasse (oder: Oberklasse davon) geh\u00f6rt. Er hat aber einen schlechten Ruf, weil er oft ein Anzeichen daf\u00fcr ist, dass man nicht wirklich objektorientiert programmiert, weil sich seine Verwendung oft ersetzen l\u00e4sst durch ordentliche Vererbung und \u00fcberschriebene Methoden. Hier gibt es aber keine andere L\u00f6sung. Zugegeben: Man kann f\u00fcr Spielobjekt-Klassen ein eigenes Typ-Attribut einf\u00fchren und es sich mit <code>getTyp()<\/code> geben lassen, und das als Entscheidungskriterium hernehmen. Dann hat jedes Kokosnussobjekt ein Attribut <code>String typ = \"kokosnuss\"<\/code>, was mir aber auch nicht gef\u00e4llt. Aber immerhin k\u00e4me ich so um das Erkl\u00e4ren von instanceof herum.<\/p>\n\n\n\n<p>So oder so habe ich ein Problem. Nehmen wir an, ich habe Patronen, mit einem Attribut <code>int anzahl<\/code>, und Pistolen mit einem Attribut <code>boolean geladen<\/code>. Es k\u00f6nnte auch ein Zauberstab mit Ladungen sein, oder Goldm\u00fcnzen:<\/p>\n\n\n\n<pre class=\"wp-block-code has-small-font-size\"><code>class Patrone extends Spielobjekt {\n\n  void anwendenAuf(Spielobjekt o) {\n    if (o instanceof Pistole) {\n      if (((Pistole) o).geladen == true) {\n        \/\/ nichts, Pistole ist bereits geladen\n      }\n      else {\n        ((Pistole) o).geladen = true; \/\/ Pistole ist jetzt geladen\n        anzahl = anzahl-1;  \/\/ der Patronenhaufen wird um 1 reduziert\n        if (anzahl == 0 ) { \n          entfernenAusInventar(this); \/\/ Patronenhaufen wird evtl. geloescht\n        }\n      }\n    }\n  }\n\n}<\/code><\/pre>\n\n\n\n<p>Wenn ich in <code>anwendenAuf<\/code> auf das \u00fcbergebene Objekt zugreifen m\u00f6chte, muss ich einen Cast machen, also das Objekt manuell einer Unterklasse zuweisen. Das kann zu einem Fehler w\u00e4hrend des Ausf\u00fchrens f\u00fchren, wenn das Objekt gar nicht zu dieser manuell zugewiesenen Klasse geh\u00f6rt. Wenn es gar nicht zu dieser manuell zugewiesenen Klasse geh\u00f6ren <em>kann,<\/em> wird bereits beim Compilieren\/\u00dcbersetzen ein Fehler gemeldet. Dieses Casten ist f\u00fcr Sch\u00fcler auch nicht leicht nachzuvollziehen, und auch eher schlechter Stil, wenn es denn anders geht. Aber: Es geht wohl nicht.<\/p>\n\n\n\n<p>Sp\u00e4ter sieht das dann so aus:<\/p>\n\n\n\n<p><img loading=\"lazy\" decoding=\"async\" class=\"alignnone size-full wp-image-9799\" src=\"https:\/\/www.herr-rau.de\/wordpress\/archiv\/inselspiel2.png\" alt=\"Benutzeroberfl\u00e4che Inselspiel\" width=\"402\" height=\"333\" srcset=\"https:\/\/www.herr-rau.de\/wordpress\/archiv\/inselspiel2.png 402w, https:\/\/www.herr-rau.de\/wordpress\/archiv\/inselspiel2-150x124.png 150w, https:\/\/www.herr-rau.de\/wordpress\/archiv\/inselspiel2-300x249.png 300w\" sizes=\"auto, (max-width: 402px) 100vw, 402px\" \/><br>Wenn man zuerst auf das Schwert und dann auf eine Kuh klickt, verschwindet die Kuh aus dem Inventar und drei Rindfleisch tauchen auf.<\/p>\n\n\n\n<p>Hmmm&#8230; wenn man eine Methode <code>anwendenAuf (Spielobjekt [])<\/code> einf\u00fchrt, kann man auch das Durchlaufen von Arrays \u00fcben. Mal sehen, wie ich das einbauen kann.<\/p>\n\n\n\n<p><strong>Fu\u00dfnote<\/strong>:<\/p>\n\n\n\n<p>Eine verlockende Sackgasse ist folgender Gedanke, mit dem der urspr\u00fcngliche Plan, verschiedene <code>anwendenAuf<\/code>-Methoden zu haben, doch noch verwirklicht werden k\u00f6nnte, wenn es den ginge.<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">Class c = o.getClass(); \/\/ wird zur Laufzeit bestimmt\nc oNeu = (c) o; \/\/ m\u00fcsste beim Compilieren \u00fcberpr\u00fcft werden k\u00f6nnen\nanwendenAuf(c)<\/pre>\n\n\n\n<p>Man l\u00e4sst sich von dem Spielobjekt o die Klasse geben, und castet dann o auf seine tats\u00e4chliche Klasse. Aber das geht nun einmal nicht, compiliert nicht einmal. Kurz: Ich kann nicht auf eine Klassentyp casten, der in einer Variablen gespeichert ist, weil dann bei der Compilierung nicht \u00fcberpr\u00fcft werden kann, ob das \u00fcberhaupt ein grunds\u00e4tzlich m\u00f6glicher Cast w\u00e4re. Denn in einer Variablen kann ja alles stecken. Das wei\u00df man erst zur Laufzeit.<\/p>\n\n\n\n<p><strong>Weitere Designfragen:<\/strong><\/p>\n\n\n\n<p>(1) Diese Regeln, was geschehen soll, wenn man das Messer auf die Kokosnuss anwendet &#8211; wo sollen die hin? Man kann es machen wie oben beschrieben, dann ist jede Klasse zust\u00e4ndig f\u00fcr sich selber. Wenn eine neue Klasse (etwa: H\u00fchnchen) eingef\u00fchrt werden soll, muss man in allen Klassen, deren Objekte etwas mit den Objekten der neuen Klasse anfangen k\u00f6nnen sollen, den Code \u00e4ndern. Das ist umst\u00e4ndlich. Stattdessen k\u00f6nnte man eine einzige Klasse haben, die alle m\u00f6glichen Kombinationen von <code>anwendenAuf(Spielobjekt o1, Spielobjekt o2) <\/code> behandelt. Gro\u00dfer Vorteil: F\u00fchre ich neue Klassen ein, muss ich nur in einer Klasse Code \u00e4ndern. Nachteil: Diese Methode wird ziemlich gro\u00df, da die Kombinationsm\u00f6glichkeiten mit der Anzahl der Klassen schnell steigen, auch wenn, zugegeben, nur die potentiell m\u00f6glichen Kombinationen implmenetiert werden m\u00fcssen. Bei 5 Typen gibt es maximal 25 Kombinationen, bei 10 Typen schon 100, das w\u00e4chst geradezu&#8230; <a href=\"https:\/\/www.herr-rau.de\/wordpress\/2012\/03\/das-p-np-problem-teil-1-was-schwierig-ist.htm\">nein, nicht exponentiell, noch lange nicht, aber polynomiell\/quadratisch<\/a>. Und vor allem kann ich es dann nicht mehr so machen, dass jede Sch\u00fclerin und jeder Sch\u00fcler ihre eigenen Anwendungsregeln in eigenen Klassen erstellen.<\/p>\n\n\n\n<p>(2) Richtig viel Arbeit kann ich mir machen, wenn ich Verb-Objekte einf\u00fchre, also etwa eine Klasse <code>Schneiden<\/code>, die enth\u00e4lt, was geschieht, wenn ich ein Objekt des Interface-Typs &#8222;KannSchneiden&#8220; auf ein Objekt des Interface-Typs &#8222;KannGeschnittenWerden&#8220; anwende. So \u00e4hnlich ist das zwar bei Sprachen f\u00fcr Textadventures, aber so gr\u00fcndlich will ich gar nicht sein.<\/p>\n\n\n\n<p>(3) Wenn ich vorher wei\u00df, welche Unterklassen von Spielobjekt es geben soll, dann kann ich in die Spielobjekt-Oberklasse 30 leere, gegebenenfalls zu \u00fcberschreibende Methoden platziere: <code>anwendenAuf(Kokosnuss k) {}, anwendenAuf(Palme p) {}<\/code> und so weiter. Dazu kommt dann eine zentrale Methode:<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">void anwendenAuf(Spielobjekt o) { \n  if (o instanceof Messer) anwendenAuf( (Kokosnuss) o); \n  else if (o instanceof Messer) anwendenAuf( (Palme) o); \n}<\/pre>\n\n\n\n<p>Diese Methode verteilt die Aufrufe dann auf die glechnamigen Methoden mit den korrekten Argumenten. Dann greift wieder das <em>overriding <\/em>und damit <em>dynamic binding<\/em>. Dann kann ich wieder meine urspr\u00fcngliche Idee umsetzen &#8211; separate Methoden f\u00fcr jeden Spielobjekttyp. Allerdings muss ich halt jedesmal den Code in dieser einen Klasse anpassen, wenn eine neue Unterklasse von Spielobjekt eingef\u00fchrt wird.<\/p>\n\n\n\n<p>(4) Keine L\u00f6sung habe ich bisher f\u00fcr das Folgende: Wenn ich ein Messer auf eine Kokosnuss anwende, geschieht dann das gleiche, wie wenn ich eine Kokosnuss auf ein Messer anwende? Wenn ich die Patronen anwende auf die Pistole, soll das gleiche passieren wie bei der Anwendung der Pistole auf die Patronen? Wenn nein, kein Problem, dann passt alles. Wenn ja&#8230; die Messerklasse entscheidet nur, wenn das Messer angewendet wird. In welcher Klasse soll stehen, was geschieht, wenn ich die Kokosnuss anwende? Wenn das in Kokosnuss ist, f\u00fchrt das zu Code-Dopplung, und wo sonst? Hier f\u00e4llt mir nur ein, doch L\u00f6sung (1) zu w\u00e4hlen.<\/p>\n\n\n\n<p>Links, die zeigen, dass viele Leute schon vor dem gleichen Problem standen:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><a href=\"https:\/\/stackoverflow.com\/questions\/2768748\/using-inheritance-and-polymorphism-to-solve-a-common-game-problem\">https:\/\/stackoverflow.com\/questions\/2768748\/using-inheritance-and-polymorphism-to-solve-a-common-game-problem<\/a><\/li>\n\n\n\n<li><a href=\"https:\/\/stackoverflow.com\/questions\/36722057\/polymorphism-doesnt-work-in-method-arguments-in-java\">https:\/\/stackoverflow.com\/questions\/36722057\/polymorphism-doesnt-work-in-method-arguments-in-java<\/a><\/li>\n\n\n\n<li><a href=\"https:\/\/stackoverflow.com\/questions\/1572322\/overloaded-method-selection-based-on-the-parameters-real-type\">https:\/\/stackoverflow.com\/questions\/1572322\/overloaded-method-selection-based-on-the-parameters-real-type<\/a><\/li>\n\n\n\n<li><a href=\"https:\/\/stackoverflow.com\/questions\/2790144\/avoiding-instanceof-in-java\">https:\/\/stackoverflow.com\/questions\/2790144\/avoiding-instanceof-in-java<\/a><\/li>\n\n\n\n<li><a href=\"https:\/\/sites.google.com\/site\/steveyegge2\/when-polymorphism-fails\">https:\/\/sites.google.com\/site\/steveyegge2\/when-polymorphism-fails<\/a><\/li>\n\n\n\n<li><a href=\"https:\/\/stackoverflow.com\/questions\/19017258\/static-vs-dynamic-binding-in-java\">https:\/\/stackoverflow.com\/questions\/19017258\/static-vs-dynamic-binding-in-java<\/a><\/li>\n<\/ul>\n\n\n\n<p>(Und die Linksammlung erkl\u00e4rt, warum es nervig ist, wenn der Webfilter der Schule stackoverflow.com sperrt.)<\/p>\n","protected":false},"excerpt":{"rendered":"<p>(11 Kommentare.) &#8230;die sich als aufw\u00e4ndiger und lehrreicher herausgestellt hat, als ich dachte. Es begann damit, dass ein Kollege mir von dem Computerspiel erz\u00e4hlte, das ihn gerade besch\u00e4ftigte: Als Schiffbr\u00fcchiger auf einer Insel sammelt man unter anderem Gegenst\u00e4nde ein und erntet Pflanzen, jagt Tiere und arbeitet mit Werkzeugen. Zum Beispiel kann man mit einem Messer [&hellip;]<\/p>\n","protected":false},"author":2,"featured_media":9799,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_jetpack_memberships_contains_paid_content":false,"footnotes":""},"categories":[25],"tags":[227,233],"class_list":["post-9753","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-informatik","tag-informatik","tag-programmierprojekte"],"jetpack_featured_media_url":"https:\/\/www.herr-rau.de\/wordpress\/archiv\/inselspiel2.png","jetpack_sharing_enabled":true,"jetpack_likes_enabled":true,"_links":{"self":[{"href":"https:\/\/www.herr-rau.de\/wordpress\/wp-json\/wp\/v2\/posts\/9753","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.herr-rau.de\/wordpress\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.herr-rau.de\/wordpress\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.herr-rau.de\/wordpress\/wp-json\/wp\/v2\/users\/2"}],"replies":[{"embeddable":true,"href":"https:\/\/www.herr-rau.de\/wordpress\/wp-json\/wp\/v2\/comments?post=9753"}],"version-history":[{"count":3,"href":"https:\/\/www.herr-rau.de\/wordpress\/wp-json\/wp\/v2\/posts\/9753\/revisions"}],"predecessor-version":[{"id":56636,"href":"https:\/\/www.herr-rau.de\/wordpress\/wp-json\/wp\/v2\/posts\/9753\/revisions\/56636"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/www.herr-rau.de\/wordpress\/wp-json\/wp\/v2\/media\/9799"}],"wp:attachment":[{"href":"https:\/\/www.herr-rau.de\/wordpress\/wp-json\/wp\/v2\/media?parent=9753"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.herr-rau.de\/wordpress\/wp-json\/wp\/v2\/categories?post=9753"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.herr-rau.de\/wordpress\/wp-json\/wp\/v2\/tags?post=9753"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}