Seite 2 von 3

Verfasst: Freitag 20. April 2007, 16:04
von BlackJack
Naja, ein bisschen besser ist es schon, aber noch nicht perfekt.

Es wird wieder Code wiederholt und zwar die `join()`-Aufrufe mit den Einträgen. `self.menue_eintraege` ist ein Attribut das meiner Meinung nach zuviel ist. Das gehört nicht zum Zustand eines Menüs. Der ist mit `eingeklappt` und den Menütexten ausreichend definiert. Und `self.menue` ist auch nicht notwendig. Mal davon abgesehen, das ich in der `__init__()` das Menü nicht ausgeben würde, hätte ein ``print self`` völlig gereicht.

Also mal von vorne. Ein "klappbares" Menü braucht Daten und zwar die Menüpunkte und die Information ob es gerade ein- oder ausgeklappt ist. Die notwendigen Daten werden in der `__init__()`-Methode gesetzt.

Dann braucht ein Objekt noch "Verhalten" in Form von Methoden. Das Menü soll man ein- und ausgeklappen können, also je eine Methode dafür. Was man dabei nur ändern muss ist `self.eingeklappt` damit man jederzeit abfragen kann in welchem Zustand sich das Menü gerade befindet.

Und weil man das Menü auch ausgeben möchte, gibt's eine Funktion die aus den Informationen die den Zustand beschreiben eine Zeichenkette zusammenbaut. Das ist der einzige Teil wo wirklich etwas interessantes passiert.

Die Zeichenkette besteht aus der Kopfzeile an die die numerierten Menüpunkte angehängt werden. Wenn das Menü eingeklappt ist, dann wird dieser Vorgang nach dem dritten Punkt abgebrochen.

Wenn das Menü lang genug ist, um ein- oder ausgeklappt zu werden muss man jetzt entscheiden welcher der beiden Menüpunkte zum klappen angezeigt werden muss.

Zum Schluss noch der Beenden-Menüpunkt und die Fusszeile. Ergebnis:

Code: Alles auswählen

# -*- coding: utf-8 -*-

class Menue(object):
    kopfzeile = '----------Menü-----------'
    option_a = 'a für ausklappen'
    option_e = 'e für einklappen'
    option_E = 'E für Ende'
    fusszeile = '-------------------------'
    
    def __init__(self, eintraege, eingeklappt=True):
        self.eintraege = eintraege
        self.eingeklappt = eingeklappt
    
    def __str__(self):
        result = [self.kopfzeile]
        for i, eintrag in enumerate(self.eintraege):
            if self.eingeklappt and i > 2:
                break
            result.append('%d. %s' % (i + 1, eintrag))
        if len(self.eintraege) > 2:
            if self.eingeklappt:
                result.append(self.option_a)
            else:
                result.append(self.option_e)
        result.extend((self.option_E, self.fusszeile))
        return '\n'.join(result)
    
    def ausklappen(self):
        self.eingeklappt = False
        
    def einklappen(self): 
        self.eingeklappt = True


if __name__ == '__main__':
    menue = Menue(('Umfang Rechteck',
                   'Fläche Rechteck',
                   'Umfang Dreieck',
                   'Fläche rechtwinkliges Dreieck',
                   'Umfang Kreis'))
    print menue
    menue.ausklappen()
    print menue
    menue.einklappen()
    print menue

Verfasst: Freitag 20. April 2007, 19:43
von EyDu
BlackJack hat geschrieben:Naja, ein bisschen besser ist es schon, aber noch nicht perfekt.
Möchtest du damit etwa andeuten, dass du mit deiner Korrektur die perfekte Lösung abgeliefert hast ;-) ?

Je nach dem, ob beim Öffnen oder Schließen des Menüs noch etwas getan werden muss, würde ich die beiden dazugehörigen Methoden entfallen lassen (sonst führen wir hier als nächstes noch Setter- und Getter-Methoden ein :-) ):

Code: Alles auswählen

    def ausklappen(self):
        self.eingeklappt = False
        
    def einklappen(self): 
        self.eingeklappt = True

Verfasst: Samstag 21. April 2007, 23:26
von rolgal_reloaded
@blackjack

gefällt mir schon gut. Momentan bastel ich an einer Lösung mit 2 Klassen. Menue und KlappMenue. Erstens hätte man zuerst ein ganz super einfaches Beispiel für OOP, kann es schön ausbauen und das Prinzip der Vererbung auch noch gut zeigen.

Bin noch nicht fertig, stell es dann mal rein

@EyDu

Und wie würde es dann konkret aussehen ohne den entsprechenden Methoden?

LG

rolgal_reloaded

Verfasst: Sonntag 22. April 2007, 10:27
von EyDu
rolgal_reloaded hat geschrieben:Und wie würde es dann konkret aussehen ohne den entsprechenden Methoden?
Naja, das ist gar nicht so kompliziert. Dazu verwende ich einfach mal das letzte Beispiel von BlackJack:

Code: Alles auswählen

if __name__ == '__main__':
    menue = Menue(('Umfang Rechteck',
                   'Fläche Rechteck',
                   'Umfang Dreieck',
                   'Fläche rechtwinkliges Dreieck',
                   'Umfang Kreis'))
    print menue
    menue.eingeklappt = False
    print menue
    menue.eingeklappt = True
    print menue
Wenn du natürlich nach dem Einklappen oder Aufklappen zeichnen willst, würde ich die Methoden etwas abgeändert beibehalten:

Code: Alles auswählen

class Menue(object):
    ...
    
    def ausklappen(self):
        self.eingeklappt = False
        print self
        
    def einklappen(self): 
        self.eingeklappt = True
        print self
    
    ...

if __name__ == '__main__':
    menue = Menue(('Umfang Rechteck',
                   'Fläche Rechteck',
                   'Umfang Dreieck',
                   'Fläche rechtwinkliges Dreieck',
                   'Umfang Kreis'))
    menue.ausklappen()
    menue.einklappen()
Das Beispiel ist jetzt zwar nicht mehr 100%-ig identisch, aber meine Intention sollte deutlich werden.

Verfasst: Sonntag 22. April 2007, 14:12
von rolgal_reloaded
EyDu hat geschrieben:
rolgal_reloaded hat geschrieben:Und wie würde es dann konkret aussehen ohne den entsprechenden Methoden?
Naja, das ist gar nicht so kompliziert. Dazu verwende ich einfach mal das letzte Beispiel von BlackJack:

Code: Alles auswählen

if __name__ == '__main__':
    menue = Menue(('Umfang Rechteck',
                   'Fläche Rechteck',
                   'Umfang Dreieck',
                   'Fläche rechtwinkliges Dreieck',
                   'Umfang Kreis'))
    print menue
    menue.eingeklappt = False
    print menue
    menue.eingeklappt = True
    print menue
Wenn du natürlich nach dem Einklappen oder Aufklappen zeichnen willst, würde ich die Methoden etwas abgeändert beibehalten:

Code: Alles auswählen

class Menue(object):
    ...
    
    def ausklappen(self):
        self.eingeklappt = False
        print self
        
    def einklappen(self): 
        self.eingeklappt = True
        print self
    
    ...

if __name__ == '__main__':
    menue = Menue(('Umfang Rechteck',
                   'Fläche Rechteck',
                   'Umfang Dreieck',
                   'Fläche rechtwinkliges Dreieck',
                   'Umfang Kreis'))
    menue.ausklappen()
    menue.einklappen()
Das Beispiel ist jetzt zwar nicht mehr 100%-ig identisch, aber meine Intention sollte deutlich werden.
Sorry, nicht wirklich. Was das bringt bleibt mir noch ein Geheimnis.
Aber das mag durchaus auch an mir liegen:-)

Liebe Grüße

rolgal_reloaded

Verfasst: Sonntag 22. April 2007, 18:45
von rolgal_reloaded
So jetzt habe ich das mal umgesetzt.

Ich erhoffe mir da didaktische Vorteile, wissen tu ich es natürlich nicht.
Zur Einführung in OOP könnte man also zuerst mal nur das erste Beispiel machen. Was noch nicht den Megamehrwert gegenüber einer anderen Lösung bietet. Dann könnte man dahingehend, dass es erst richtig interessant wird, wenn man Methoden zur Manipulation des Objekts hat, zuerst sowas wie die Methode hinzufuegen definieren, dann schrittweise die Idee eines Klappmenüs aufbringen und die Umsetzung, dann langsam beginnen. (Einen kompletten Vortrag zu meinen didaktischen Überlegungen spar ich mir jetzt, wenns recht ist, ggg)
Die Idee eintraege als lokale Variable in __str__ zu definieren finde ich auch nicht schlecht.

Die Frage aller Fragen aber natürlich ist: Was meinen die Pythonmeister hier dazu?

Code: Alles auswählen

class Menue:    

    kopf = "----------Menü-----------\n"
    option_E = "E für Ende\n"
    fuss = "-------------------------"    
    
    def __init__(self, eintraege):       
        self.eintraege = eintraege 

    def __str__(self):
        eintraege = [str(i + 1) + ". " + eintrag + "\n" for i, eintrag in enumerate(self.eintraege)]
        eintraege = "".join(eintraege)
        return self.kopf + eintraege + self.option_E + self.fuss 

##    def hinzufuegen(self, eintrag):
##        self.eintraege.append(eintrag)


class KlappMenue(Menue):    

    option_a = "a für ausklappen\n"
    option_e = "e für einklappen\n"
    
    def __init__(self, eintraege, eingeklappt = True):
        self.eingeklappt = eingeklappt
        self.eintraege = eintraege
        
    def __str__(self):
        eintraege = [str(i + 1) + ". " + eintrag + "\n" for i, eintrag in enumerate(self.eintraege)]

        if self.eingeklappt:
            eintraege = "".join(eintraege[:3])
            return self.kopf + eintraege + self.option_a + \
                   self.option_E + self.fuss
        else:
            eintraege = "".join(eintraege)
            return self.kopf + eintraege + self.option_e + \
                   self.option_E + self.fuss
    
    def ausklappen(self):
        self.eingeklappt = False
        
    def einklappen(self):
        self.eingeklappt = True
   

if __name__ == "__main__":

    menue = KlappMenue(["Umfang Rechteck",
                        "Fläche Rechteck",
                        "Umfang Dreieck",
                        "Fläche rechtwinkliges Dreieck",
                        "Umfang Kreis"])

    


LG

rolgal_reloaded

Verfasst: Sonntag 22. April 2007, 19:05
von BlackJack
Finde ich als Beispiel nicht so besonders. Der Vorteil von Vererbung ist ja hauptsächlich das man schon vorhandene Code in der Basisklasse in einer Unterklasse wiederverwenden kann. Das wird hier überhaupt nicht gemacht, die Vererbung ist damit überflüssig.

Die `__init__()` hätte auch eher so aussehen müssen:

Code: Alles auswählen

    def __init__(self):
        Menue.__init__(self, eintraege)
        self.eingeklappt = eingeklappt

Verfasst: Sonntag 22. April 2007, 19:08
von rolgal_reloaded
BlackJack hat geschrieben:Finde ich als Beispiel nicht so besonders. Der Vorteil von Vererbung ist ja hauptsächlich das man schon vorhandene Code in der Basisklasse in einer Unterklasse wiederverwenden kann. Das wird hier überhaupt nicht gemacht, die Vererbung ist damit überflüssig.

Die `__init__()` hätte auch eher so aussehen müssen:

Code: Alles auswählen

    def __init__(self):
        Menue.__init__(self, eintraege)
        self.eingeklappt = eingeklappt
Schau mal ich habe der Basisklasse noch eine Methode spendiert und oben noch was in der Erläuterung eingefügt.
Ausserdem werden ja sehr wohl Klassenattribute vererbt.
Geht ja nur darum übersichtlich Prinzipien darzulegen.

das mit __init__ ist klar.

LG

rolgal_reloaded

Verfasst: Sonntag 22. April 2007, 21:43
von EyDu
rolgal_reloaded hat geschrieben:Geht ja nur darum übersichtlich Prinzipien darzulegen.
Wenn ich von OOP keine Ahnung HÄTTE :D würde mich diese Menge an Code wahrscheinlich erschlagen. Ich würde bei dem guten alten Beispiel mit Fahrzeugen bleiben: Autos, Motorräder, Fahrräder, Schiffe, Amphibienfahrzeuge, ...

Wenn man das noch einigermaßen klug aufbaut, kann man gleich einige hübsche Entwurfsmuster mit abarbeiten.

Verfasst: Sonntag 22. April 2007, 22:17
von rolgal_reloaded
EyDu hat geschrieben:
rolgal_reloaded hat geschrieben:Geht ja nur darum übersichtlich Prinzipien darzulegen.
Wenn ich von OOP keine Ahnung HÄTTE :D würde mich diese Menge an Code wahrscheinlich erschlagen. Ich würde bei dem guten alten Beispiel mit Fahrzeugen bleiben: Autos, Motorräder, Fahrräder, Schiffe, Amphibienfahrzeuge, ...

Wenn man das noch einigermaßen klug aufbaut, kann man gleich einige hübsche Entwurfsmuster mit abarbeiten.
1. Wird ja niemand mit der ganzen Menge Code konfrontiert.
Wir beginnen mal nur mit der Basisklasse.
Selbst die kann man zunächst noch viel einfacher gestalten.
Z. b. dass man die "\n" nicht generiert uvm.

2. Die Beispiele mit Fahrzeugen udgl. sind eben unbrauchbar. Die sind meiner Meinung nur geeignet um einem Programmierer, einer Programmiererin OOP darzulegen, wahrscheinlich sogar nur für solche, die zum ersten mal OOP in Pyhton machen wollen.


Wenn ich mit der Fahrzeugklasse in einem BORG anrücke, dann gehen die mir auf die Barrikaden - zu Recht.
Denn schlussendlich hat nämlich der Schüler, die Schülerin gar nichts davon.

Die Menüs hingegen können in vielen Programmen, die wir erstellt haben importiert werden und tatsächlich Verwendung finden.
Und wenn man es wie oben besprochen entsprechend aufbaut, kann man fast alle Prinzipien der OOP demonstrieren und dessen Sinn auch mit einem erfahrbaren Nutzen begreifbar machen.


Liebe Grüße

rolgal_reloaded

Verfasst: Sonntag 22. April 2007, 23:16
von BlackJack
Die Beispiele mit den Fahrzeugen, geometrischen Objekten, Tieren oder Bankkonten sind die klassischen Beispiele, die in vielen Lehrbüchern und Lehrveranstaltungen für alle möglichen Programmiersprachen benutzt werden. Die sind zugegebenermassen nicht "nützlich" da sie sehr stark vereinfacht und künstlich sind, aber diese Menüklasse finde ich auch nicht besonders gut. In gewisser Weise schlechter, da sie sehr konstruiert wirkt ─ das würde man doch nie so schreiben.

Und zu dem Zeitpunkt wo man Klassen ins Spiel bringt, muss das Zielpublikum schon "Programmierer" sein. Mindestens soweit, dass die Grundkonstrukte der Sprache und Funktionen verstanden sind.

Verfasst: Sonntag 22. April 2007, 23:25
von rolgal_reloaded
BlackJack hat geschrieben:Die Beispiele mit den Fahrzeugen, geometrischen Objekten, Tieren oder Bankkonten sind die klassischen Beispiele, die in vielen Lehrbüchern und Lehrveranstaltungen für alle möglichen Programmiersprachen benutzt werden. Die sind zugegebenermassen nicht "nützlich" da sie sehr stark vereinfacht und künstlich sind, aber diese Menüklasse finde ich auch nicht besonders gut. In gewisser Weise schlechter, da sie sehr konstruiert wirkt ─ das würde man doch nie so schreiben.
Warum nicht? Wenn man viele kleine Module gebastelt hat, denen ein Benutzerinterface (Textbasis) verpassen will, sehe ich keinen Grund warum man das nicht so lösen sollte. Rein praktisch gesehen würde ich mich schlussendlich auch auf eine Klasse beschränken, was man aber mit dem Beispiel sich noch für Möglichkeiten eröffnet habe ich schon dargelegt.
Und was daran konstruierter sein soll als an einer Fahrzeugklasse weiss ich wirklich nicht.

Bei der Gelegenheit kann man noch was gut vermitteln.

Hast ein Modul, das nur ein Menü mit 3 Punkten braucht, dann importier auch nur das. Soll heissen: greifst auf ein Modul zu, schau was es beinhaltet und was du wirklich brauchst und mach nicht immer
from modul import *

bzw. bei uns

from menues import *, sondern from menus import menue
oder welche Menüs auch immer (vielleicht Untermenüs??) es noch geben wird.

Nein, nein,....ich lass mir schon was sagen von dir, aber da hast mir noch nicht wirkliche Gegenargumente geliefert, die meine Argumente für dieses OOPbeispiel entkräften.

Und zu dem Zeitpunkt wo man Klassen ins Spiel bringt, muss das Zielpublikum schon "Programmierer" sein. Mindestens soweit, dass die Grundkonstrukte der Sprache und Funktionen verstanden sind.
Sind sie ja. Ausserdem sollen hier nicht alle Programmierer werden, sondern im Sinne der Allgemeinbildung mit Programmierung im Informatikunterricht konfrontiert werden, die Sprache ist Python und daher sollte man weitestgehend alle Themen ansprechen.

Dass sie danach nicht selber Programme entwerfen und schreiben können ist schon klar.

Aber in Musik sagt ja auch niemand, dass man Fugen nur einem Komponisten erklärt. In Tonsatz, einem Pflichtgegenstand in einem Musikstudium muss jeder mal ein paar Takte dieser Gattung schreiben.
Und ja, es ist sinnvoll, weil man Schnittstellen für das Verständnis anderer Wissensbereiche herstellen kann.
Damit wären wir beim Sinn von Allgemeinbildung.

Liebe Grüße

rolgal_reloaded

Verfasst: Montag 23. April 2007, 09:25
von BlackJack
Die Frage wieso man das nicht so schreiben würde hast Du fast schon selbst beantwortet, indem Du sagst, Du würdest auch nur *eine* Klasse verwenden. Womit Du hoffentlich die ohne "klappen" meinst. Das ist einfach eine komische Konstruktion. Womit wir beim konstruiert wären: Bei den Fahrzeugklassen ist auf der einen Seite klar, dass es nur Beispiele sind, man kann sich aber vorstellen das mit entsprechenden Veränderungen etwas "richtiges" daraus wird. Bei dem Menü könnte man den Eindruck gewinnen das wäre tatsächlich etwas was man so benutzen könnte/würde, wobei ich hier das Klappmenü meine, es ist aber nur ein Beispiel wo Vererbung und "klappen" reingequetscht wurde um etwas zu zeigen. Dabei kommen die wichtigen Punkte von Vererbung aber gar nicht so deutlich zum tragen.

Zum Zielpublikum: Du hast gesagt für die klassischen Beispiele müsste man schon Programmierer sein. Jetzt sagst Du das Zielpublikum ist das auch. Wo war jetzt das Problem? Diese Fahrzeug/Tier/Figuren/…-Beispiele finden sich durchgängig in Literatur die sich an Programmieranfänger wendet.

Verfasst: Montag 23. April 2007, 10:03
von rolgal_reloaded
BlackJack hat geschrieben:Die Frage wieso man das nicht so schreiben würde hast Du fast schon selbst beantwortet, indem Du sagst, Du würdest auch nur *eine* Klasse verwenden. Womit Du hoffentlich die ohne "klappen" meinst. Das ist einfach eine komische Konstruktion. Womit wir beim konstruiert wären: Bei den Fahrzeugklassen ist auf der einen Seite klar, dass es nur Beispiele sind, man kann sich aber vorstellen das mit entsprechenden Veränderungen etwas "richtiges" daraus wird. Bei dem Menü könnte man den Eindruck gewinnen das wäre tatsächlich etwas was man so benutzen könnte/würde, wobei ich hier das Klappmenü meine, es ist aber nur ein Beispiel wo Vererbung und "klappen" reingequetscht wurde um etwas zu zeigen. Dabei kommen die wichtigen Punkte von Vererbung aber gar nicht so deutlich zum tragen.
Ist es bei einem Programm das nur 3 ( - kann auch 5 sein, egal - ) Einträge kennt ein Menü zu erzeugen, auf das Methoden angewendet werden kann, die es niemals braucht? Ich denke nein.
Ich denke inzwischen eher: wenn man noch einige Typen von Menüs definiert ist der Ansatz sinnvoll - auch für die Praxis. Wobei ich das noch nicht ausprobiert habe.

Was kommt nicht deutlich zu tragen?
Es werden Klassenattibute vererbt, der Konstruktor der Unterklasse aufgerufen und eine Methode vererbt.

Wichtig ist für uns, mich folgendes:
Behandelte Themen, Prinzipien etc. müssen in ihrem Nutzen erfahrbar werden. Und da kannst du Kopf stehen.
Mit Menüklassen, die dann tatsächlich Anwendung finden wird das in der Schule wo ich unterrichte eher der Fall sein, als mit einer Klasse Autos - siehe Einstieg in Python - was soll denn so ein Unsinn?

Dasselbe mit Funktionen: da habe ich einiges von Lingl übernommen, weil gut der Nutzen einer Funktion rauskommt.

Wenn ich in der Schule sowas mache:

Code: Alles auswählen

def saghallo():
    print "Hallo"
dann sehen sie mich mit großen Augen an und fragen mich, warum ich das so kompliziert mache. Freilich für echte Programmierer sind Beispiele mit Pseudocode ok.

Nochmal: Fahrzeugklassen bleiben Pseudocode und Menüklassen kann ich verwenden, was für die Pädagogik noch wichtiger ist. Ich kann bereits erstelle Arbeiten damit erweitern.
Spätestens mit den Methoden hinzufügen oder den Methoden im KlappMenue wird klar was der Mehrwert von OOP darstellt.

Das geht mit opel.beschleunigen(20) nicht.

Ich glaube du bist jetzt in der Bewertung zu sehr Profi - Programmierer mit seinem professionellen Umfeld. Es geht hier um ganz andere Kriterien.
Geh mal in eine Schule wie die meine, halte dich an den Lehrplan und komm mit Fahrzeugklassen daher.

Wie kann man übrigens aus einer Fahrzeugklasse was richtiges machen???

Zum Zielpublikum: Du hast gesagt für die klassischen Beispiele müsste man schon Programmierer sein. Jetzt sagst Du das Zielpublikum ist das auch. Wo war jetzt das Problem?

So gesehen keines, ich habe was anderes gemeint - mit obigen Ausführungen jetzt vielleicht klar.

Anfangs war für mich das Problem mit der Realisierung von Menüs mit Klassen, dass ich ein Brett vor dem Kopf hatte, wie man bestimmte Methoden ohne Megaaufwand realisieren könnte. Siehe 1. Posting.
Gerade hier hast du mir wieder mal sehr auf die Sprünge geholfen.
Vielen Dank nochmal!

Liebe Grüße

rolgal_reloaded

Verfasst: Montag 23. April 2007, 10:53
von BlackJack
Was für Menütypen denn? Wenn schon das Klappmenü ein künstliches Beispiel ist was man nicht verwenden würde.

Ich denke man sollte schon ein komplettes Beispiel als Ziel haben, das alle Aspekte von Vererbung beisammen hat und vererbte Attribute und Methoden die in Unterklassen verwendet werden und auch Polymorphie beinhaltet. Eben um zeigen zu können was Klassen ausmacht und wo die Vorteile liegen.

Was ist der Nutzen von so einem Klappmenü? Was ist der Nutzen von Klassen? Gibt es überhaupt nicht-künstliche Beispiele die nicht trivial sind, wo man sich nicht fragt, warum nehme ich da nicht einfach eine Funktion? Klassen sind im Grunde erst ab einer gewissen Komplexität des Programms wirklich nützlich. Erfahrenere Programmierer benutzen sie auch an Stellen, wo sie nicht zwingend notwendig sind, aber das eben aus der Erfahrung heraus, dass Programme dazu tendieren mit der Zeit komplexer zu werden. Wobei Python noch das zusätzliche "Problem" hat, dass alles Objekt ist, inklusive Funktionen. Wo andere Sprachen für das Observer-Entwurfsmuster schon Interfaces und Klassen brauchen, kann man in Python einfach eine Callback-Funktion übergeben.

Und wieso kann man mit Fahrzeugklassen nicht den Mehrwert von OOP darstellen? `opel.beschleunigen()` wird wahrscheinlich auf geerbte Attribute aus einer `Fahrzeug`-Klasse zurückgreifen. Um einen neuen Autotyp zu implementieren kann man also auf vorhandene Funktionalität zurückgreifen, aber wenn man will, diese auch komplett ersetzen/überschreiben.

Wenn man eine Liste mit verschiedenen konkreten Fahrzeugttypen hat, kann man prima Polymorphie zeigen. Es wird immer "automagisch" die richtige Methode ausgeführt, weil ein Objekt "weiss" was es ist.

Was "richtiges" kann man daraus auch machen indem der Lehrer ein Framework vorgibt, wo die Schüler ihre eigenen Fahrzeuge programmieren können und dann irgendetwas damit machen müssen. Ein Rennen, oder vielleicht irgendwelche Nutzfahrzeuge die zusammen eine Aufgabe erfüllen müssen.

Und gerade im Schulkontext können geometrische Formen als "praktisch" angesehen werden. Es gibt gemeinsame Methoden an denen man Polymorphie zeigen kann und gewisse Beziehunghierarchien zwischen Formen, die man als Vererbung oder Aggregation modellieren kann.