Klassenaufbau bei größeren Programmen, MVC
Verfasst: Samstag 20. Februar 2010, 18:47
Hallo,
bei größeren Programmen versuche ich, Berechnungen und GUI nach dem "Model-View-Controller"-Modell zu trennen. Da ich das ja nirgendwo in einer (Hoch-) Schule gelernt habe, wollte ich mal fragen, ob "man das so macht" oder doch lieber anders.
Also hier erstmal mein "Skeleton", das ich dann jeweils ausbaue, in vier Dateien:
1. "main.py":
2. "model.py":
3. "view.py":
4. "data.py":
Hier sind auch schon ein paar Berechnungen: Ich verwende Tkinter als GUI-Toolkit und möchte, daß die Anwendung unter Windows und Linux direkt läuft (am besten auch MacOS-X: Könnte da bitte jemand ein paar Angaben zu verfügbaren und geeigneten Fonts und Fontgrößen machen). Außerdem möchte ich das Hauptfenster auf dem Bildschirm zentrieren. Dazu brauche ich die Auflösung und die Größe des Fensters mit den jeweils unterschiedlichen Fonts. Das Dumme ist, daß ich diese Größe erst abfragen kann, wenn Tkinter schon aktiv ist, also das Hauptfenster schon dargestellt wird. Na ja, vielleicht kann auch jemand dazu was sagen, aber darum geht es hier nicht hauptsächlich.
Sondern: Das, was zu berechnen ist, fasse ich meist in weiteren Unterklassen von "Model" zusammen und gebe jeweils "Model" der __init__-Funktion der Unterklasse mit. Das heißt, "Model" ist dann der Unterklasse bekannt. Da "Model" auch "Controller" kennt (und "Controller" "View") können Daten aus den Unterklassen über "Model" und "Controller" auch an "View" weitergeleitet werden (und umgekehrt).
Ein Problem ist, ich bin immer versucht, aus der Unterklasse auf diesem Weg direkt auf "View" zuzugreifen.
Und ich bin ebenso versucht, aus "View" heraus, direkt Daten in "Model" oder den Unterklassen zu manipulieren.
Ist das ok, oder soll man immer alles stur über Funktionen in "Controller" und zusätzlich der jeweiligen manipulierten Klasse abwickeln (das wird dann aber manchmal ziemlich aufwendig und lang)?
Darf also auch eine Instanz direkt Werte in einer anderen Instanz verändern oder soll man das vermeiden?
Anders gefragt: Wenn man ein Objekt "flasche" und ein Objekt "person" hätte, dürfte
dann auch direkt
setzen? Oder müßte man immer in "flasche" eine Funktion "wirdgeleert()" haben, die dann von "person.trinkt()" aufgerufen wird und "self.istvoll = False" setzt?
Soweit erstmal. Bin diesmal echt auf eure Antworten gespannt ...
Gruß
bei größeren Programmen versuche ich, Berechnungen und GUI nach dem "Model-View-Controller"-Modell zu trennen. Da ich das ja nirgendwo in einer (Hoch-) Schule gelernt habe, wollte ich mal fragen, ob "man das so macht" oder doch lieber anders.
Also hier erstmal mein "Skeleton", das ich dann jeweils ausbaue, in vier Dateien:
1. "main.py":
Code: Alles auswählen
#!/usr/bin/env python
#-*- coding: iso-8859-1 -*-
import os
import model
import view
class Controller:
def __init__(self):
self.osname = os.name
self.model = model.Model(self)
self.view = view.View(self, self.model)
def run(self):
self.view.showMain()
def quit(self):
self.view.mw.destroy()
if __name__ == "__main__":
application = Controller()
application.run()
Code: Alles auswählen
#!/usr/bin/env python
#-*- coding: iso-8859-1 -*-
import data
class Model:
def __init__(self, controller):
self.controller = controller
self.data = data.ModelData()
Code: Alles auswählen
#!/usr/bin/env python
#-*- coding: iso-8859-1 -*-
import Tkinter as tk
import tkFileDialog
import ScrolledText
import data
class View:
def __init__(self, controller, model):
self.controller = controller
self.model = model
self.resolution = (1024, 768)
self.data = data.ViewData()
self.fonts = self.data.getFonts(self.controller.osname)
def showMain(self):
self.mw = tk.Tk()
self.mw.title("Title")
self.mw.geometry(self.getGeometry( (66, 60) ))
self.mw.option_add("*font", self.fonts["app"])
self.mw.bind(sequence = "<Control-q>", func = lambda e: self.controller.quit())
self.lab = tk.Label(self.mw,
text = "Hallo")
self.lab.pack()
self.fr1 = tk.Frame(self.mw)
self.fr1.pack()
self.btnexit = tk.Button(self.fr1,
text = "Exit",
command = self.controller.quit)
self.btnexit.pack()
# self.mw.after(2000, self.showWinsize)
self.mw.mainloop()
def showWinsize(self):
print self.mw.winfo_width()
print self.mw.winfo_height()
def getGeometry(self, winsize):
x = (self.resolution[0] - winsize[0]) // 2
y = (self.resolution[1] - winsize[1]) // 2
if x < 0:
x = 0
if y < 0:
y = 0
return "+" + str(x) + "+" + str(y)
Code: Alles auswählen
#!/usr/bin/env python
#-*- coding: iso-8859-1 -*-
class ViewData:
def getFonts(self, osname):
fonts = {"posix" : {"app" : '"Suse Sans" 16',
"small" : '"Suse Sans" 12',
"text" : '"Courier" 20' },
"nt" : {"app" : 'Arial 10',
"small" : 'Arial 8',
"text" : '"courier new" 10' }}
return fonts[osname]
class ModelData:
def __init__(self):
pass
Sondern: Das, was zu berechnen ist, fasse ich meist in weiteren Unterklassen von "Model" zusammen und gebe jeweils "Model" der __init__-Funktion der Unterklasse mit. Das heißt, "Model" ist dann der Unterklasse bekannt. Da "Model" auch "Controller" kennt (und "Controller" "View") können Daten aus den Unterklassen über "Model" und "Controller" auch an "View" weitergeleitet werden (und umgekehrt).
Ein Problem ist, ich bin immer versucht, aus der Unterklasse auf diesem Weg direkt auf "View" zuzugreifen.
Und ich bin ebenso versucht, aus "View" heraus, direkt Daten in "Model" oder den Unterklassen zu manipulieren.
Ist das ok, oder soll man immer alles stur über Funktionen in "Controller" und zusätzlich der jeweiligen manipulierten Klasse abwickeln (das wird dann aber manchmal ziemlich aufwendig und lang)?
Darf also auch eine Instanz direkt Werte in einer anderen Instanz verändern oder soll man das vermeiden?
Anders gefragt: Wenn man ein Objekt "flasche" und ein Objekt "person" hätte, dürfte
Code: Alles auswählen
person.trinkt(flasche)
Code: Alles auswählen
flasche.istvoll = False
Soweit erstmal. Bin diesmal echt auf eure Antworten gespannt ...
Gruß