Schlechter Programmierstil?!

Wenn du dir nicht sicher bist, in welchem der anderen Foren du die Frage stellen sollst, dann bist du hier im Forum für allgemeine Fragen sicher richtig.
derrick
User
Beiträge: 34
Registriert: Mittwoch 8. Juni 2011, 20:32

Abend Leute,
ich schreibe in letzter Zeit hobbymäsig einige Programme zu allen möglichen Aufgaben und stehe immer wieder vor den gleichen Problemen. Vielleicht könnt ihr mir in diesem Thread helfen mit diesen Mal aufzuräumen. Ich zeig euch mal exemplarisch eine Aufgabe:

Entwickle eine Python-Anwendung zur Simulation eines Bankautomaten. Der Anwender soll einen Benutzernamen (der die EC-Karte repräsentiert) und eine dazugehörige PIN eingeben, um Zugriff auf sein Konto zu erhalten. Insgesamt soll die Beispiel-Anwendung drei Konten mit unterschiedlichen Benutzernamen und PINs unterstützen. Ist das Einloggen erfolgreich, kann der Anwender zwischen Kontostandanzeige und Auszahlung eines Betrags wählen. Das Programm soll in einer Endlosschleife laufen, um mehrmaliges Einloggen in den Bankautomaten zu ermöglichen. Setze die drei Konten auf beliebige Werte, um das Programm zu testen, und logge dich mehrmals mit jedem Benutzer ein, um den Kontostand anzuzeigen und Geld abzuheben.

Den Code von mir dazu gibts hier(http://www.python-forum.de/pastebin.php?mode=view&s=200).

Und hier sind meine Probleme:
1)
Dauernd muss ich diese globalen Variablen benutzen ,da ich sonst nicht hinkomm.
Würde logout etwa None zurückgeben müsste ich ja in main schreiben:
k = logout(),was aber nicht geht da ich dieses dict benutze um Befehle aufzurufen,d.h. jede Funktion müsste
was zurückgeben was ich in k speichern kann. Deshalb:
2)
Ist so ein Menudict überhaupt sinnvoll ,eigentlich setzt es ja voraus ,dass ich jede Funktion mit denselben Parametern
aufrufen will,welche Alternativen gibt es (auser Kommandozeilenargumente)
3)
Wie schaffe ich es anständig Eingaben zu prüfen: schreibe ich entweder für jede Funktion eine eigene Prüfungsfunktion, oder eine große Test-Funktion die von verschiedenen Funktionen mit einem eindeutigen Parameter aufgerufen wird, und dann für diese aufrufende Funktion die Eingaben prüft
4)
Wie gehe ich an eine Aufgabe wie o.g. objektorientiert heran?
Z.B.:Ist es der Kunde der die geld_abheben Funktion besitzt oder doch der Automat?usw...

So das wärs was mich gerade interessiert, möglicherweise mach ich aber noch ganz anderes falsch. Jeder Hinweis auf solches ist daher ebenso willkommen!

derrick
Benutzeravatar
cofi
Python-Forum Veteran
Beiträge: 4432
Registriert: Sonntag 30. März 2008, 04:16
Wohnort: RGFybXN0YWR0

Ad 1) Du hast einen globalen Kunden. Macht das Sinn? Wäre es nicht besser 10 Automaten aufstellen zu können? Der Kunde sollte ein Attribut von `Automat` sein.

Ad 2) Ja, aber nicht in jeder Situation. Die Einschränkungen hast du ja bereits erkannt: Die Menüpunkte brauchen Gemeinsamkeiten.

Ad 3) Die 2. Möglichkeiten ist ein Wartungsalptraum. Diese Funktion muss _alle_ anderen Funktionen kennen und dazu auch noch ihre gewuenschten Eingaben.

Ad 4) Es gibt nicht nur einen Weg. Es kommt darauf an, was du modellieren willst. Es macht zum Beispiel Sinn, dass beide so eine Methode haben. Oder nur der Automat. Dass nur der Kunde so eine Methode hat, ist allerdings nur dann sinnvoll, wenn es einen Selbstbedienungsladen gibt ;)
problembär

Ja, Dein Programmierstil könnte besser sein. Man braucht keine globals.
Guckstu (ohne "Abheben", Python 2.x):

Code: Alles auswählen

#!/usr/bin/env python
# coding: iso-8859-1

import sys

class Kunde:

    def __init__(self, name, pin, kontostand):
        self.name = name
        self.kontostand = kontostand
        self.pin = pin

class Automat:

    def __init__(self):

        self.bekannte_kunden = [Kunde('user1', 1234, '4000'),
                                Kunde('user2', 4321, '2000'),
                                Kunde('user3', 1111, '4500')]

    def loginUser(self):

        username = raw_input("Username: ")
        pin = int(raw_input("Pin: "))

        self.user = None

        for k in self.bekannte_kunden:
            if username == k.name and pin == k.pin:
                self.user = k
                break
        if self.user:
            print("Access granted")
            return True
        else:
            print("Access denied")
            return False

    def geld_abheben(self):
        print "Noch nicht implementiert."

    def kontostand_anzeigen(self):
        print("Der aktuelle Kontostand beträgt: " + str(self.user.kontostand))

def main():
    a = Automat()

    if a.loginUser() == False:
        sys.exit(1)

    while True:
        choice = raw_input("Geld (A)bheben oder (K)ontostand anzeigen oder (L)ogout?  ")
        choice = choice.upper()
        if choice == "A":
            a.geld_abheben()
        elif choice == "K":
            a.kontostand_anzeigen()
        elif choice == "L":
            print "Bye."
            break 
        else:
            print ("'%s' is not a valid option. Try again." % choice)

if __name__ == '__main__':
  main()
Gruß
Benutzeravatar
pillmuncher
User
Beiträge: 1484
Registriert: Samstag 21. März 2009, 22:59
Wohnort: Pfaffenwinkel

ad 1: Du könntest die Variable k zum Attribut des Automaten machen (und ihr einen besseren Namen geben):

Code: Alles auswählen

class Automat: # hier bitte keine leeren Klammern anfügen.
    def __init__(self):
        self.bekannte_kunden = ...
        self.kunde = None
    ...
    def geld_abheben(self):
        ...
        self.kunde.kontostand = int(self.kunde.kontostand) - betrag
        self.kontostand_anzeigen()
    def kontostand_anzeigen(self):
        print("Der aktuelle Kontostand beträgt: " + str(self.kunde.kontostand))
    def logout(self):
        self.kunde = None
...
ad 2: Ja, so ein dict ist sinnvoll. Guido van Rossum, der Erfinder von Python, nennt das das Table Driven Command Dispatch Pattern.

ad 3: wie es im Gesamtkontext des Programms am bequemsten ist. Bei deinem Programm würde ich jede Funktion ihre Eingaben selbst prüfen lassen.

ad 4: Eine Möglichkeit ist, die Klassenstruktur aus den Use Cases zu gewinnen, zB. so:

Der Anwender soll einen Benutzernamen (der die EC-Karte repräsentiert) und eine dazugehörige PIN eingeben, um Zugriff auf sein Konto zu erhalten.

Hier haben wir einen Anwender, seinen Namen, seine Pin und sein Konto:

Code: Alles auswählen

class Anwender:
    def __init__(self, name, pin, konto):
        self.name = name
        self.pin = pin
        self.konto = konto
Insgesamt soll die Beispiel-Anwendung drei Konten mit unterschiedlichen Benutzernamen und PINs unterstützen.

Aha, wir könnten also auch das Konto zur Klasse machen, dem ein Benutzername und eine PIN zugeordnet ist (statt dass der Anwender das Konto hat):

Code: Alles auswählen

class Konto:
    def __init__(self, name, pin):
        self.name = name
        self.pin = pin
Ist das Einloggen erfolgreich, ...

Oft hört man, man solle bei der OO-Analyse Substantive suchen, die dann zu Klassen, und Verben, die dann zu Methoden würden. Ich halte das für verkehrt, und "das Einloggen" ist das beste Beispiel, warum es verkehrt ist. Wir brauchen keine Klasse:

Code: Alles auswählen

class DasEinloggen:
    ...
sondern eine Methode

Code: Alles auswählen

def einloggen(self, kunde, pin):
    ...
denn das Einloggen ist etwas, das getan wird, im Gegenstatz zB. zum Konto, das gehabt wird.

... kann der Anwender zwischen Kontostandanzeige und Auszahlung eines Betrags wählen.

Auch hier machen wir aus der Kontostandsanzeige und der Auszahlung eines Betrags Methoden:

Code: Alles auswählen

def kontostand_anzeigen(self):
    ...
def geld_abheben(self):
    ...
Das Programm soll in einer Endlosschleife laufen, um mehrmaliges Einloggen in den Bankautomaten zu ermöglichen.

Wir brauchen noch den Automaten und das Hauptprogramm:

Code: Alles auswählen

class Bankomat:
    ...
def main():
    while True:
        ...
Dein Programm ist dem schon recht ähnlich, du hast es also im Grunde nicht schlecht zergliedert. Das oben sind allerdings nur die ersten Schritte. Ich baue aus sowas erstmal ein Klassengerüst und programmiere ein bisschen drumherum, um zu sehen wie es sich anfühlt. Dann ändere ich es solang immer wieder, bis es tut was es soll und mir einigermaßen gefällt. Am Ende kommt dann zB. sowas heraus.

[EDIT]

Man kann natürlich auch das State Pattern verwenden, so wie hier.
In specifications, Murphy's Law supersedes Ohm's.
BlackJack

@pillmuncher: Also das mit den Substantiven und Klassen halte ich nicht für verkehrt, denn es wird ja nicht einfach nur gesagt man soll Substantive zu Klassen machen, sondern die Substantive sind *Kandidaten* für Klassen. Das sagt nicht das alle Substantive Klassen sein sollen und auch nicht das man keine Klasse haben darf, die nicht als Substantiv im Text vorkommt. Nachdenken muss man schon noch. :-)
derrick
User
Beiträge: 34
Registriert: Mittwoch 8. Juni 2011, 20:32

Also vielen Dank für eure ausführlichen Beiträge werde mir gleich heute Mittag
die Links durchlesen und das Programm verändern. Die wichtigste Änderung ist wohl
dem Automaten den Kunden (bzw. das Konto) als Attribut zu geben.
Viele Grüße
derrick
Benutzeravatar
pillmuncher
User
Beiträge: 1484
Registriert: Samstag 21. März 2009, 22:59
Wohnort: Pfaffenwinkel

BlackJack hat geschrieben:@pillmuncher: Also das mit den Substantiven und Klassen halte ich nicht für verkehrt, denn es wird ja nicht einfach nur gesagt man soll Substantive zu Klassen machen, sondern die Substantive sind *Kandidaten* für Klassen. Das sagt nicht das alle Substantive Klassen sein sollen und auch nicht das man keine Klasse haben darf, die nicht als Substantiv im Text vorkommt. Nachdenken muss man schon noch. :-)
Aber die Regel geht ja oft so: Substantive sind Kandidaten für Klassen und Verben sind Kandidaten für Methoden. Wenn man es bloß dabei belässt, wird aus 'Das Einloggen geschieht so-und-so' niemals eine Methode einloggen(), weil Substantive eben keine Kandidaten für Methoden sind. Wie du sagst, nachdenken muss man schon noch. Vielleicht hätte ich nicht schreiben sollen, es sei verkehrt, sondern es sei naiv, sich allein auf solch allzu platte Regeln zu verlassen.

Jorge Luis Borges beschreibt in Tlön, Uqbar, Orbis Tertius eine Sprache ohne Substantive. Hier ein Auszug aus dem Wikipedia-Artikel:

Eine der imaginären Sprachen von Tlön kennt keine Substantive: Es gibt unpersönliche Verben, die durch einsilbige Suffixe oder Präfixe adverbieller Art näher bestimmt werden. So gibt es kein Wort für „Mond“, aber ein Verb, das man mit „monden“ oder „mondieren“ übersetzen könnte. Das tlönische Äquivalent des Satzes „Der Mond ging über dem Fluß auf“ heißt Hlör u fang axaxaxas mlö, was wörtlich übersetzt etwa lautet: Empor hinter dauerfließen mondet es.

Ob die Tlönesen wohl jemals Objektorientierung erfunden haben?
In specifications, Murphy's Law supersedes Ohm's.
BlackJack

@pillmuncher: Verben sind ja prima Kandidaten für Funktionen (natürlich auch nur mit nachdenken :-)), also haben sie vielleicht eine funktionale Programmiersprache mit Closures erfunden. Und wie ja bekannt sein sollte: „closures are a poor man's objects.”

Und hier mal völlig Off-Topic wie man es nicht machen sollte (CBM BASIC V2):

Code: Alles auswählen

   10 READ N:DIM UN$(N),UP$(N),UB(N)
   20 FOR I=1 TO N:READ UN$(I),UP$(I):UB(I)=1000:NEXT
   30 DATA 3,PETER,12345,PAUL,4711,MARY,42
   40 PRINT"{CLR}BANKOMAT":PRINT"========":PRINT
   50 INPUT"NAME";N$:INPUT"PIN";P$:AI=-1
   60 FOR I=0 TO N:IF UN$(I)=N$ AND UP$(I)=P$ THEN AI=I:I=N
   70 NEXT
   80 IF AI<>-1 THEN 110
   90 PRINT"NAME ODER PIN IST FALSCH! (TASTE)"
  100 POKE 198,0:WAIT 198,1:GET A$:GOTO 40
  110 PRINT:PRINT"GUTEN TAG, "UN$(AI)"."
  120 PRINT:PRINT"1) KONTOSTAND"
  130 PRINT"2) GELD ABHEBEN"
  140 PRINT"3) AUSLOGGEN"
  150 INPUT"AUSWAHL (1-3)";A:IF A<1 OR A>3 THEN 150
  160 ON A GOSUB 190,200,230
  170 IF AI=-1 THEN 40
  180 GOTO 120
  190 PRINT:PRINT"DER KONTOSTAND BETRAEGT"UB(AI)"EUR":RETURN
  200 INPUT"BETRAG";A
  210 IF A>UB(AI) THEN PRINT"NICHT GENUG GELD AUF DEM KONTO":RETURN
  220 UB(AI)=UB(AI)-A:RETURN
  230 AI=-1:RETURN
lunar

@pillmuncher: Natürlich gibt es keine vernünftigen Verben, wenn man die Verben künstlich substantiviert. So spricht aber niemand (zumindest außerhalb von Behörden), weil es sich eher dämlich anhört. Unterhalte Dich mit irgendeiner x-beliebigen Person auf der Straße über Bankautomaten: Die wird nicht sagen „Das Anmelden geschieht, indem man seine Karte in den Automaten schiebt und seine PIN eingibt“, sondern „Man meldet sich am Automaten an, indem man seine Karte in den …“. Und da ist „anmelden“ plötzlich eben doch ein Verb …
derrick
User
Beiträge: 34
Registriert: Mittwoch 8. Juni 2011, 20:32

So hab mir gerade dieses State Pattern Entwurfsmuster angeschaut und noch eine Frage.
In Java müsste ich ja einen Setter schreiben damit diese einzelnen Zustandsobjekte den Zustand
des Kontextes eigenständig ändern können.
Versteh ich das richtig das du Pillmuncher die Zustände einfach den Kontext erweitern lässt und
was hat es dann mit dem self.__class__ = Ausgeloggt bzw. self.__class__ = Eingeloggt auf sich?
BlackJack

@derrick: Damit ändert man zur Laufzeit den Typ von `self`. Kann man machen. Muss man aber nicht. Wäre mir persönlich zu ”magisch”.
derrick
User
Beiträge: 34
Registriert: Mittwoch 8. Juni 2011, 20:32

Alles klar danke
Benutzeravatar
pillmuncher
User
Beiträge: 1484
Registriert: Samstag 21. März 2009, 22:59
Wohnort: Pfaffenwinkel

derrick hat geschrieben:Versteh ich das richtig das du Pillmuncher die Zustände einfach den Kontext erweitern lässt
Ja, so könnte man das formulieren.
derrick hat geschrieben:was hat es dann mit dem self.__class__ = Ausgeloggt bzw. self.__class__ = Eingeloggt auf sich?
In "Head First: Design Patterns" steht auf Seite 410: The State Pattern allows an object to alter its behavior when its internal state changes. The object will appear to change its class. Und in der englischen Pattern-Bibel steht auf Seite 309: Changing the behavior for a particular request could be accomplished by changing the object's class at run-time, but this is not possible in most object-oriented programming languages. In Python werden Methoden-Aufrufe auf einem Objekt o automatisch an dessen Klassen-Objekt o.__class__ delegiert, wenn kein gleichnamiges Attrribut in o.__dict__ gefunden wird. Da man an o.__class__ einfach andere Klassen binden kann, kann man sich so den Overhead sparen, der in statischeren Programmiersprachen nötig ist. In Java zB. müsste in o.foo() explizit o.state.foo() aufgerufen werden.
In specifications, Murphy's Law supersedes Ohm's.
Benutzeravatar
pillmuncher
User
Beiträge: 1484
Registriert: Samstag 21. März 2009, 22:59
Wohnort: Pfaffenwinkel

BlackJack hat geschrieben:@derrick: Damit ändert man zur Laufzeit den Typ von `self`. Kann man machen. Muss man aber nicht. Wäre mir persönlich zu ”magisch”.
Für mich fängt Magie erst bei Metaklassen an :wink:
In specifications, Murphy's Law supersedes Ohm's.
Benutzeravatar
pillmuncher
User
Beiträge: 1484
Registriert: Samstag 21. März 2009, 22:59
Wohnort: Pfaffenwinkel

lunar hat geschrieben:@pillmuncher: Natürlich gibt es keine vernünftigen Verben, wenn man die Verben künstlich substantiviert. So spricht aber niemand (zumindest außerhalb von Behörden), weil es sich eher dämlich anhört. Unterhalte Dich mit irgendeiner x-beliebigen Person auf der Straße über Bankautomaten: [...] Und da ist „anmelden“ plötzlich eben doch ein Verb …
Die Unterscheidung künstlich vs. natürlich ist doch selbst künstlich. Natürlich in unserem Verhalten (zB.wie wir reden) erscheint uns das, was wir immer schon so gemacht haben, und alles andere als künstlich.

Wenn wir OO-Analyse betreiben, sollten wir IMO zwar mit den alltäglich Beschreibungen der Benutzer bzw. Auftraggeber (AKA Use Cases) beginnen, aber wir wären schlecht beraten, wenn die in unseren Programmen inkarnierten Konzepte 1:1 dieselben wären, wie die in den Beschreibungen. Erstens kommen in den Beschreibungen typischerweise keine Listen, Arrays, polymorphe Methoden-Aufrufe uä. vor. Zweitens lässt sich vieles abstrahieren, was in den Beschreibungen konkret dargestellt wird, sodass man eben auch auf einem abstrakteren Niveau das Problem überdenken und lösen kann.

Martin Fowler schlägt zB. in Analysis Patterns eine Trennung in eine Wissens- und eine operationale Ebene vor, wobei die Wissens-Ebene dazu dient, der operationalen Ebene Typen- und andere Beschränkungen aufzuerlegen. Ein Beispiel von ihm ist die hierarchische Organisations-Struktur einer großen Firma. Angenommen Use Cases der Art: "Das Sales Office reportet die Umsätze monatlich an Leitung des Geschäftsbereichs" und "Die Geschäftsbereichsleitung reportet die gesammelten Umsätze ihrer untergeordneten Sales Offices quartalsmäßig an die Geschäftsleitung" . Jetzt könnte man einfach Klassen wie SalesOffice und Division schreiben, die einander kennen und gegenseitig ihre Methoden aufrufen. Aber statt die Klassen fest zu verdrahten, könnte man auch die Verbindungen auf der Wissens-Ebene als eigenständige Klassen reifizieren. Im Programm führt das zB. dazu, dass Umsätze nicht mehr direkt von SalesOffice-Objekten an Division-Objekte gemeldet werden, sondern anhand der auf der Wissens-Ebene hinterlegten Regeln wird das benötigte Empfänger-Objekt ermittelt, dem gegenüber man reportpflichtig ist, und auf dem wird dann polymorph die entsprechende Methode aufgerufen. Ein Vorteil ist, dass es durch eine solche Entkoppelung möglich wird, dass ein Objekt verschiedenen orthogonalen Hierarchien angehören kann, zB. kann die Personalabteilung eine ganz andere Hierarchie benötigen. Oder man kann die Hierarchie umstellen, ohne die operationalen Klassen anzufassen, da man nur Änderungen innerhalb der Wissens-Ebene durchführen muss. Vielleicht sollte man diesen Prozess Orthogonalization of Concerns nennen.

Jedenfalls ist die Methode Fowlers deutlich elaborierter, als die Substantiv-Verb-Analyse. Zu glauben, man könne jederzeit aus den Formulierungen von Laien (zu denen man oft selbst gehört) plus etwas Intuition die Grundstruktur eines Programms ableiten, halte ich für falsch.
In specifications, Murphy's Law supersedes Ohm's.
derrick
User
Beiträge: 34
Registriert: Mittwoch 8. Juni 2011, 20:32

Hm wenn du schon aus "Head First: Design Patterns" zitierst nutz ich die Gelegenheit dochmal um nachzufragen
ob das Buch empfehlenswert ist.
Grüße derrick
Benutzeravatar
pillmuncher
User
Beiträge: 1484
Registriert: Samstag 21. März 2009, 22:59
Wohnort: Pfaffenwinkel

derrick hat geschrieben:Hm wenn du schon aus "Head First: Design Patterns" zitierst nutz ich die Gelegenheit dochmal um nachzufragen
ob das Buch empfehlenswert ist.
Teils-teils. Die Beispiele sind recht gut gewählt, weil einfach zu verstehen. Es macht Spaß, das Buch zu lesen, bzw. es immer mal wieder durchzublättern. Die Diskussions-Richtung im Buch geht immer ungefähr so: Praktisches Problem --> kurzes Durchspielen falscher Lösungsansätze --> Lösung anhand eines Design Patterns --> theoretische Aufarbeitung --> Einordnung unter abstrakte Prinzipien der OO.

Ein weiterer Vorteil für manche ist, dass die Beispiele in Java geschrieben sind. In Gamma et al. sind die Beispiele in C++ oder Smalltalk.

Was mir nicht so gut gefallen hat, waren die nur kurz auf jeweils zwei Seiten dargestellten Design Patterns, die im Buch sonst keinen Platz mehr gefunden haben. Das Visitor Pattern zB. wird völlig verkehrt dargestellt. Da hätte ich es besser gefunden, einen zweiten Band rauszubringen oder das einfach ganz wegzulassen.

Alles in Allem war es kein Fehlkauf. Wenn man das Buch von Gamma et al. dagegen schon kennt und versteht, wird man das Head First Buch eher als Unterhaltungsliteratur ansehen :wink: Nicht weil es schlecht wäre, sondern weil man das, was drin steht, ja schon kennt.

Gruß,
Mick.
Zuletzt geändert von pillmuncher am Mittwoch 15. Juni 2011, 02:56, insgesamt 1-mal geändert.
In specifications, Murphy's Law supersedes Ohm's.
lunar

@pillmuncher: Niemand hat gesagt, dass man Beschreibungen als unmittelbare Grundlage eines Modells nutzen sollte. Sie dienen aber als erster Anhaltspunkt für einen ersten Entwurf. Nicht mehr, aber auch nicht weniger.

Ebenso spielt auch das, was „man schon immer gemacht“ hat, eine wichtige Rolle. Warum? Weil man darin halt die meiste Erfahrung hat, weil es offenbar bisher immer einigermaßen funktioniert hat, und weil es von vielen verstanden wird. Entwurfsmuster sind nichts anderes als die Formalisierung solchen Erfahrungswissens.

Mit Erfahrung und Überlegung kommt man beim Entwurf auch mit simplen Methoden recht weit. Entwurfsmustern und Analysemethoden sind hilfreich, aber keinesfalls obligatorisch. Ihre Anwendung ist insbesondere kein Ersatz für für gesunden Menschenverstand und sorgfältige Überlegung. Die stumpfe Anwendung von Entwurfsmustern ist viel eher schädlich. Bei Deiner State Pattern-Lösung beispielsweise steht die Komplexität der Lösung in keinem Verhältnis mehr zur Trivialität des Problems. Entwurfsmustern sind eben kein Allheilmittel, denn egal was GoF sagt, dass Ändern der Klasse zur Laufzeit ist in Python trotzdem nicht unbedingt empfehlenswert :)
Benutzeravatar
pillmuncher
User
Beiträge: 1484
Registriert: Samstag 21. März 2009, 22:59
Wohnort: Pfaffenwinkel

lunar hat geschrieben:Ebenso spielt auch das, was „man schon immer gemacht“ hat, eine wichtige Rolle. Warum? Weil man darin halt die meiste Erfahrung hat, weil es offenbar bisher immer einigermaßen funktioniert hat, und weil es von vielen verstanden wird. Entwurfsmuster sind nichts anderes als die Formalisierung solchen Erfahrungswissens.
Ich gebe dir da natürlich größtenteils recht. Ich finde jedoch, dass man die Konventionalität des Bestehenden immer im Auge behalten sollte, und ggf. aus den bestehenden Mustern ausbrechen sollte, AKA Fortschritt. Manches wird dabei funktionieren, manches aber auch nicht. Das wird aber beim Althergebrachten ebenso sein, dass nur manches davon in einer neuen Situation funktionert.
lunar hat geschrieben:Mit Erfahrung und Überlegung kommt man beim Entwurf auch mit simplen Methoden recht weit. Entwurfsmustern und Analysemethoden sind hilfreich, aber keinesfalls obligatorisch. Ihre Anwendung ist insbesondere kein Ersatz für für gesunden Menschenverstand und sorgfältige Überlegung. Die stumpfe Anwendung von Entwurfsmustern ist viel eher schädlich. Bei Deiner State Pattern-Lösung beispielsweise steht die Komplexität der Lösung in keinem Verhältnis mehr zur Trivialität des Problems. Entwurfsmustern sind eben kein Allheilmittel, denn egal was GoF sagt, dass Ändern der Klasse zur Laufzeit ist in Python trotzdem nicht unbedingt empfehlenswert :)
Mein Ziel war es gerade, die lokale Komplexität in den Methoden zu verringern. In jeder Methode braucht man so nur auf den derzeitigen Zustand Rücksicht nehmen, und nicht auf andere mögliche Zustände. Dass man vorher in jeder Methode Code zur Diskriminierung derselben Zustände wiederholen musste, widersprach nicht nur DRY, sondern war ein Hinweis darauf, dass diese Zustände globalerer Art waren und entsprechend eine Lösung auf globalerer Ebene erforderten.

Ich habe so immerhin alle if-Statements eliminieren können, bis auf die, die der Validierung von User-Eingaben dienen. Zustands-Steuerung mittels If-Statements sollte in der OO-Programmierung eigentlich gar nicht vorkommen, sondern sollte polymorph über Methoden erfolgen.

Man könnte es übrigens auch so machen :wink:
Zuletzt geändert von pillmuncher am Mittwoch 15. Juni 2011, 02:59, insgesamt 2-mal geändert.
In specifications, Murphy's Law supersedes Ohm's.
problembär

@pillmuncher: Danke für die schönen, auch weiterführenden Beiträge. Nett zu lesen, und handeln meist von interessanten Dingen, die ich noch gar nicht kannte.
Zum Code hier allerdings: Meinst Du nicht, daß Deine Konzepte alle ein bißchen zu kompliziert sind? Ich meine, mein Vorschlag oben ging ja von dem aus, was derrick zuvor schon geschrieben hatte. Noch ein paar Änderungen hier und da, und dann läuft das alles doch schon ganz gut und auf recht einfache Weise.

Mit "State Patterns" und "Design Patterns" überforderst Du doch auch seinen Lehrer. :mrgreen:

Gruß
Antworten