Seite 1 von 1

mvc + db

Verfasst: Mittwoch 27. Februar 2008, 22:41
von crazymichel1
hi,
ich plane gerade ein etwas größeres projekt, bin aber noch völlig unerfahren, was softwaredesign anbelangt. vielleicht könnt ihr mir mit euerer erfahrung ein wenig auf die sprünge helfen:

besagtes projekt erfordert u.a., dass eine liste aus einer datenbank (oder textdatei) über eine wxpython-gui oder tui angezeigt wird. über diese sollen die datensätze dann auch verändert werden können.
ich habe dabei versucht, so objektorientiert wie möglich zu denken. da ich meinen eigenen entwürfen etwas misstrauisch gegenüber stand, habe ich recherchiert und bin dabei auf das mvc-design pattern gestoßen.

demnach brauche ich also ein model, das alle datenbestände enthält, u.a. eine abstrakte liste mit einträgen.
außerdem eine view, die dann u.a. eine grafische version einer liste mit grafischen einträgen enthalten würde.
und dann den controller, der die beiden verbindet.

das wars jetzt mit der sicherheit, ab jetzt ist hinter jeder zeile ein fragezeichen zu lesen:
- die view erfährt von einer änderung des models durch eine art observer, der z.B. feststellt, dass sich eintrag 1 in liste a des models geändert hat. die view wird deshalb eintrag 1 in ihrer grafischen liste a anweisen, sich zu updaten.

- wird nun in der gui eintrag 1 von liste a geändert, wird dies von wxpython als event registriert. zuständig für die nun nötigen veränderungen ist aber der controller. dieser soll entscheiden, was zu tun ist, ggf. berechnungen mit hilfe anderer klassen durchführen und die änderungen am model vornehmen (konkret model.listea.eintrag1 verändern). und da wären jetzt zwei varianten für mich denkbar:
a) die view leitet events nur an den controller weiter, d.h. sie teilt ihm lediglich mit: "eintrag 1 in liste a hat sich geändert"
b) die view trifft bereits erste entscheidungen: "löscheEintrag(a, 1)"

- wie werden jetzt aber die daten gespeichert? im zusammenhang mit mvc habe ich leider nie etwas von io-operation gelesen. irgendwie muss ich den datenbestand im arbeitsspeicher ja mit dem datenbestand auf der festplatte synchronisieren.
a) ich könnte vielleicht das model bei jeder änderung anweisen, sich in der datenbank zu speichern bzw. im konstruktor die daten aus der datenbank zu laden.
b) oder aber ich interpretiere das model als die datenbank selbst, dann müsste ich aber wohl darauf verzichten, meine daten als objekt abzuspeichern, da datenbanken ja keine objekte kennen.


irgendwie hab ich das dumme gefühl, dass ich grad viel zu kompliziert denke :roll:

Verfasst: Donnerstag 28. Februar 2008, 00:38
von BlackJack
Für die Speicherung wäre hier das Modell zuständig. Das kann durchaus eine Abstraktionsschicht über einer Datenbank sein. Und man kann Objekte auch auf die üblichen relationalen Datenbanken abbilden. Entweder "per Hand", oder mit einem Object Relational Mapper (ORM). Zwei beliebte in Python sind SQLObject und SQLAlchemy.

Sicht und Steuerung fasse ich oft zusammen. Die beiden zu trennen macht IMHO nur Sinn, wenn es mehrere Sichten für das Modell gibt, die sich eine Implementierung einer Steuerung teilen können. Wenn ich dass nicht schon im voraus weiss, lege ich beides zusammen. Wenn nötig kann man das später ja immer noch refaktorisieren. Aber das ist Geschmackssache.

Re: mvc + db

Verfasst: Donnerstag 28. Februar 2008, 00:40
von Gnushi
crazymichel1 hat geschrieben:ich plane gerade ein etwas größeres projekt, bin aber noch völlig unerfahren, was softwaredesign anbelangt. vielleicht könnt ihr mir mit euerer erfahrung ein wenig auf die sprünge helfen:
Ich habe eine Reihe von richtig tollen angefangenen Programmen auf meiner Festplatte, die aufgrund mangelnder Planung nie etwas geworden sind. Von daher sind Deine Überlegungen sehr gut und helfen dir.

Folgender Vorschlag kann vieleicht nützlich sein:
Plane Dein Programm mit Hilfe von kleinen bunten und beschrifteten Kästchen, das muss kein UML sein, darf dem aber gerne nahe kommen. Für alles, wo es keine Symbole gibt, erfindest Du welche. Um MVC brauchst Du Dich an der Stelle nur wenig zu kümmern, so lange Du Deine GUI und Programmlogik voneinander trennst. Erfinde auf Papier oder in Kivio oder so einfach Symbole, male Pfeile dran und bastel Dir so das Programm schonmal zurecht. Dann solltest Du wissen, WANN etwas passiert, WAS als nächstes passiert und was der Benutzer machen kann und darf.

Vielleicht hilft es ja.

Viel Erfolg!

GnuShi

Verfasst: Samstag 1. März 2008, 13:18
von sma
Vielleicht hilft der folgende Code, das Grundprinzip von MVC zu erläutern. Das Model hält die Daten und kann andere darüber informieren, wenn sie Daten ändern. Der View ist die die Anzeige zuständig und lässt sich daher vom Model (das ihn nicht direkt kennt) informieren, wenn eine neue Darstellung not tut. Der Controller arbeitet mit dem View zusammen, steuert irgendwie die Anwendung und ändern z.B. als Folge von Benutzereingaben das Model. Der folgende Code kann die Triade nicht korrekt abbauen und nur Model ist eigentlich generisch genug, aber das Prinzip wird vielleicht klar...

Code: Alles auswählen

class Model:
  def __init__(self, **kw):
    self.__dict__.update(kw)
    self.__dict__['observers'] = []

  def __setattr__(self, name, value):
    if name not in self.__dict__ or self.__dict__[name] != value:
      self.__dict__[name] = value
      for observer in self.observers: observer.changed(self, name)

  def __delattr__(self, name):
    if name in self.__dict__:
      del self.__dict__[name]
      for observer in self.observers: observer.changed(self, name)

  def add_observer(self, observer):
    self.observers.append(observer)

class MyModel(Model):
  def __init__(self):
    Model.__init__(self, value=0)

  def __str__(self):
    return str(self.value)

class View:
  def __init__(self, model):
    self.model = model
    self.model.add_observer(self)

  def display(self):
    print "I display", self.model

  def changed(self, model, aspect):
    print "Model changed, therefore",
    self.display()

class Controller:
  def __init__(self, view):
    self.view = view
    self.view.controller = self
    self.model = view.model

  def loop(self):
    self.view.display()
    while True:
      self.model.value = input("Change value to? ")

if __name__ == '__main__':
  Controller(View(MyModel())).loop()
Stefan

Verfasst: Mittwoch 5. März 2008, 11:48
von crazymichel1
habe ich nun für jeden Datentyp in meinem Programm ein eigenes model oder fasse ich alle daten unter einem model zusammen?

danke übrigens für euere antworten, waren alle 3 sehr aufschlussreich.

Verfasst: Mittwoch 5. März 2008, 12:23
von lutz.horn
crazymichel1 hat geschrieben:habe ich nun für jeden Datentyp in meinem Programm ein eigenes model oder fasse ich alle daten unter einem model zusammen?
Ein einfacer Ansatz ist "Active Record" (http://www.martinfowler.com/eaaCatalog/ ... ecord.html), bei dem jede Modellklasse auf eine Datenbanktabelle abgebildet wird. Mit einem ORM (SQLAlchemy, Storm, ...) ist dieses Pattern sehr einfach zu implementieren.

Antwort auf Deine Frage: jeder konzeptionell zu unterscheidende Entität deines Datenmodells entspricht ein eigene Modell-Klasse, die das "Active Record"-Pattern implementiert.

Verfasst: Mittwoch 5. März 2008, 12:37
von sma
Hier möchte ich widersprechen.

Das AR-Pattern schlägt erstmal nur vor, dass man aus Datensätzen (Records) aktive Objekte macht, indem man Verhalten ergänzt. Das AR-Pattern sagt nicht, ob und wie man das ganze in Klassen aufteilt. Eine 1:1-Abbildung von Datenbank-Tabelle auf Klasse liegt zwar nahe, aber genauso gut könnte man auch alle Datensätze aller Tabellen auf nur Exemplare einer generischen AR-Klasse abbilden.

Ich würde mich dem Problem von der Darstellung her nähern. Was immer man auch als eine Einheit darstellen will, sollte von einem Modell her kommen. Etwa eine Listendarstellung wird von einem Listenmodell gestützt. Das die Liste selbst diverse Objekte aus einer Datenbank - vielleicht sogar Exemplare von verschiedenen Klassen - enthält, ist dabei erstmal nicht wichtig.

Modelle bilden dann eine Hierarchie. Ganz oben gibt es ein ApplicationModel, das den Zustand der Anwendung beschreibt. Dieser setzt sich aus weiteren Modellen zusammen. Man beachte, dass man auch Teile eines Modells nach MVC wieder als Modell betrachten kann, moderne GUI-Rahmenwerke kennen das Konzept von Bindings, das sind (komplexe) Pfade, über die man View und Modell unter Erhalt der Observer-Beziehnung verknüpfen kann, ohne dass man das explizit programmieren muss. VisualWorks-Smalltalk hatte das in den 90er Jahren, VisualAge Smalltalk auch, WPF und Flex haben es jetzt auch und feiern dieses "neue" Feature :)

Stefan