Klasseninstanzen reden miteinander

Zurück zur Übersicht


Die Frage ist, auf welche Weise Klasseninstanzen miteinander reden könnten. Dass dies auf viele verschiedene Arten realisiert werden kann ist klar. Auch ist klar, dass es für verschiedenste Anwendungsfälle jeweils andere Arten sind, die das im konkreten Fall gut erledigen. Dabei soll das Grundprinzip, dass der Zugriff auf Attribute einer Klasseninstanz ausschliesslich über die Methoden der Klasse und nicht direkt erfolgt, strikt eingehalten werden, um die Kapselung der einzelnen Objekte nicht zu verletzen.

An einer konkreten einfachen Aufgabe wollen wir mal verschiedene Möglichkeiten der Lösung durchspielen. Die Aufgabe lautet, dass eine zentrale Klasse geschaffen werden soll, an der sich andere Klassen anmelden und dort bekanntmachen. Die zentrale Klasse soll dann anhand der Anwesenheitsliste die zugeodneten Klassen nach ihren Zustand abfragen.

Braucht man ein solches Modell überhaupt? Um das zu beantworten, hier ein paar Anwendungsbeispiele:

Nun einige Beispiele mit steigendem Kompliziertheitsgrad:

Beispiel 1

"""
direkter Dialog zwischen zwei Instanzen unterschiedlicher Klassen über deren Methoden
Nur client ist hier wirklich aktiv, server reagiert nur
Die melde-funktion von server dient hier nur zur Kontrolle
""" 

class server:
   def __init__(self, wert=0):
      self.data = wert
def neu(self, wert):
   self.data = wert
def melde(self):
   return self.data

"""
server macht hier das Einfachste vom Einfachen
er merkt sich nur eine Zahl
"""

class client:
   def __init__(self, wert):
      self.wert = wert
   def setze(self):
      s.neu(self.wert)
   def frage(self):
      print s.melde()

s = server()
print s.melde()    # server in Grundstellung (wert = default)
c1 = client(123)

# nun sind zwei Instanzen geschaffen, die miteinander reden können

c1.setze()
# jetzt hat c1 wert von server neu gesetzt

s.melde()


Beispiel 2

"""
direkter Dialog zwischen Instanzen unterschiedlicher Klassen über deren Methoden
Auch hier ist nur client wirklich aktiv, server reagiert nur
Die melde-funktion von server dient nur zur Kontrolle
"""

class server:
   def __init__(self):
      self.data = []
   def hinzu(self, wert):
      self.data.append(wert)
   def melde(self):
      return self.data

"""
server macht hier schon mehr, als im Beispiel 1, er merkt sich die Zahlenwerte aller angeschlossenen client
aus Vereinfachungsgründen können diese Zahlenwerte durch client nach der Erstmeldung nicht nochmal geändert werden
"""

class client:
   def __init__(self, wert):
      self.wert = wert
      s.hinzu(wert)
   def melde(self):
      return self.wert

s = server()
print "Wertesammlung in server vorher: ", s.melde()    # server - Liste noch leer


clients = []
for i in (6, 5, 100, 19, 27):
   c = client(i)
   clients.append(c)

print "Wertesammlung in server nachher:", s.melde()

"""
wo sind eigentlich die 5 clients geblieben, die wir in der for - Schleife erzeugt haben? Sie liegen als Feld von Adresszeigern in der Liste clients und könnten dort jederzeit weiterverwendet werden. Das ginge dann so:
"""

for i in range(0, 5):
   print str(i+1) + ". client hat den Wert:", clients[i].melde()

"""
Und eben dies könnte doch auch die server - Klasse verwalten!
"""

 


Beispiel 3

"""
direkter Dialog zwischen Instanzen unterschiedlicher Klassen über deren Methoden
Hier werden sowohl client als auch server aktiv
die clients hinterlegen im Server ihre Adresse und werden durch server auf ihren Zustand befragt.
"""

class server:
   def __init__(self):
      self.data = []
   def hinzu(self, adr):
      self.data.append(adr)
   def abfrage(self):
      werte = []
      for i in self.data:
         werte.append(i.melde())
      return werte

"""
server macht hier noch mehr, als im Beispiel 2, er merkt sich die Adressen aller angeschlossenen client
Zur Abfrage holt er sich die aktuellen Werte der clients, wenn es soweit ist.
Hier können die Zahlenwerte der clients nach der Erstmeldung jederzeit geändert werden
"""

class client:
   def __init__(self, wert):
      self.wert = wert
      s.hinzu(self)
      # jetzt ist es passiert, hier geht die client-adr in die Liste und nicht der Wert
   def melde(self):
      return self.wert
   def setzneu(self, wert):
      self.wert = wert

s = server()
print "Wertesammlung in server vorher: ", s.abfrage() # server - Liste noch leer

clients = []
for i in (6, 5, 100, 19, 27):
   c = client(i)
   clients.append(c)

print "Wertesammlung in server nachher:", s.abfrage()

clients[3].setzneu(4000)
print "Wertesammlung in server, nach einer Änderung:", s.abfrage()


Bisher arbeitet server nur mit den Adressen der clients, ohne deren Namen zu kennen. Das ist für die Funktion auch nicht unbedingt erforderlich. Für die Verfolgung des Programmablaufes ist es aber oft trotzdem hilfreich. Auch dafür gibt es Möglichkeiten. Diese findet man hier.


In allen Beispielen wurde eine Nachricht von Instanzen an Instanzen gesendet. Das ist grundsätzlich auch notwendig, damit die Maschine erkennen kann, wohin was zu geben ist. Deshalb sind solche Botschaften nicht ohne weiteres in den abstrakten Klassen organisierbar. Trotzdem gibt es Methoden, die das zumindest teilweise ermöglichen.

Beispiel 1:

Eine abstrakte Klasse enthält eine Funktion zum Absenden einer Botschaft an ein Ziel das als Parameter erst zur Laufzeit übergeben wird. Hier zu finden.

Beispiel 2:

Es wird eine Informationskette aufgebaut, wobei die Information nach prüfen durch jedes Element entweder herausgenommen und ausgewertet wird oder bei "Nichtzuständigkeit" an den Nächsten weitergegeben wird. Da hier alle Objekte vom gleichen Typ sind und sich nur durch die Zählnummer unterscheiden, kann man das auf der Ebene der abstrakten Klassen organisieren. Hier zu finden.