Hallo,
ich habe ein Problem bei der objektorientierten Umsetzung eines einfachen "Schalters". Die Probelmstellung ist folgende:
Als Beispiel soll ein Haus mit vielen Räumen mit Lichtschaltern dienen. Dabei soll es einen zentralen Schalter geben der alle Lichter aus/ein schalten kann. Die Lichter sollen aber auch einzeln lokal geschaltet werden.
Nun Suche ich eine elegante Möglichkeit dies für eine Klasse Schalter zu übertragen. Meine Überlegung war eine Klasse erezugen die einen "Schalter" besitzt. Wobei der Schalter verschiedene Zustände hat (an,aus,etc). Dieser Schalter soll einmal global (für alle Objekte dieser Klasse) auf einen Zustand gestzt werden können, oder aber auch von den einzelnen Objekten (Räumen) geschaltet werden. Dabei möchte ich wenn möglich auf eine Schleife über alle Objekte der Klasse zum Schalten verzichten.
Ich hoffe ich habe mich einigermaßen verständlich asugedrückt, und freue mich über alle Anregungen + Hilfe.
Lufia
"Schalter - Objekt" programmieren
- Hyperion
- Moderator
- Beiträge: 7478
- Registriert: Freitag 4. August 2006, 14:56
- Wohnort: Hamburg
- Kontaktdaten:
So in der Art?
Code: Alles auswählen
# -*- coding: utf-8 -*-
class Schalter(object):
status = False
def __init__(self, name=u"Schalter"):
self.name = name
def __str__(self):
return u"%s ist %s!" % (self.name, "an" if self.status else "aus")
def main():
s1 = Schalter(u"s1")
print s1
s2 = Schalter(u"s2")
s2.status = True
print s2
print s1
Schalter.status = True
print s1, s2
if __name__ == "__main__":
main()
Abgesehen davon, dass ich "status" auch eher "is_on" oder so nennen würde, finde ich die Deklaration als Klassenattribut auch deplaziert. Ich würde es in der __init__ setzen.
- Hyperion
- Moderator
- Beiträge: 7478
- Registriert: Freitag 4. August 2006, 14:56
- Wohnort: Hamburg
- Kontaktdaten:
Hm ... ich dachte das wäre genau die Intention von Lufia? Ansonsten brauchste ja doch wieder eine Schleife um alle Schalter einzuschalten.lunar hat geschrieben:Abgesehen davon, dass ich "status" auch eher "is_on" oder so nennen würde, finde ich die Deklaration als Klassenattribut auch deplaziert. Ich würde es in der __init__ setzen.
Mein Ansatz:
Code: Alles auswählen
class Switch(object):
def __init__(self, state=False, master=None):
self._state = state
self.master = master
def __str__(self):
return 'Switch (%s)' % ('off', 'on ')[self.state]
@apply
def state():
def fget(self):
result = self._state
if self.master is not None:
result = result and self.master.state
return result
def fset(self, state):
self._state = state
return property(**locals())
def main():
master = Switch(True)
room_a = Switch(master=master)
room_b = Switch(master=master)
room_a.state = True
print master, room_a, room_b
master.state = False
print master, room_a, room_b
Magie!?
``@apply`` ist ja nur syntaktischer Zucker für folgende Zeile *nach* der ``def`` von `state`: ``state = apply(state)``. Und `apply()` ruft in dem Fall `state` einfach nur auf, also ``state = state()``. `state()` (also das alte) liefert ein `property`-Exemplar und das wird an `state` (neu) gebunden. Das war's auch schon.
``@apply`` ist ja nur syntaktischer Zucker für folgende Zeile *nach* der ``def`` von `state`: ``state = apply(state)``. Und `apply()` ruft in dem Fall `state` einfach nur auf, also ``state = state()``. `state()` (also das alte) liefert ein `property`-Exemplar und das wird an `state` (neu) gebunden. Das war's auch schon.
also irgendwie finde ich die Aufgabenstellung recht missglückt. Man kann die Aufgabe ja beliebig kompliziert machen...
wenn ich mit diesen Schaltern wirklich ein Haus simulieren wollte käme ich ja nie und nimmer mit einem normalen Schalter aus. Da gibt es doch schon Probleme wenn ich mir einen Raum (meinetwegen ein Flur) vorstelle und der von mehr als einem Schalter bedient werden müsste... da hört das Simulieren mit einem Schalter doch schon auf.
Um wenigstens dem Problem aus dem Weg zu gehen würde ich die Lampen als Objekte nehmen deren Zustand ich ändern kann. Schalter würden dann auf, in diesem Falle Lampen (kann ja im Endeffekt alles sein), zugreifen. Wenn dein Master halt nicht mit einer Schleife auf alle Schaltbaren Objekte zugreifen soll kann man die Schalter auch als Objekte definieren und mit den Jeweils zu schaltenden Objekten bekannt machen. So kann dann ein Schalter auch mehrere Lampen in einem Raum schalten.
Aber wie gesagt aus dem bisschen Aufgabenstellung kann ich auch noch viel komplizierter machen
wenn ich mit diesen Schaltern wirklich ein Haus simulieren wollte käme ich ja nie und nimmer mit einem normalen Schalter aus. Da gibt es doch schon Probleme wenn ich mir einen Raum (meinetwegen ein Flur) vorstelle und der von mehr als einem Schalter bedient werden müsste... da hört das Simulieren mit einem Schalter doch schon auf.
Um wenigstens dem Problem aus dem Weg zu gehen würde ich die Lampen als Objekte nehmen deren Zustand ich ändern kann. Schalter würden dann auf, in diesem Falle Lampen (kann ja im Endeffekt alles sein), zugreifen. Wenn dein Master halt nicht mit einer Schleife auf alle Schaltbaren Objekte zugreifen soll kann man die Schalter auch als Objekte definieren und mit den Jeweils zu schaltenden Objekten bekannt machen. So kann dann ein Schalter auch mehrere Lampen in einem Raum schalten.
Aber wie gesagt aus dem bisschen Aufgabenstellung kann ich auch noch viel komplizierter machen
Moin,
mein Ansatz (angelehnt an Blackjacks) schaltet durch den Master global alle Lichter entweder an oder aus, nicht, wie bei Blackjack, global aus oder auf den vorherigen Zustand:
Wobei ich das mit dem Timestamp nicht sonderlich elegant finde. Das Visitor-Pattern wäre IMO hier angesagt. Da braucht man zwar auch eine Schleife, aber was soll's?
Gruß,
Manuel
mein Ansatz (angelehnt an Blackjacks) schaltet durch den Master global alle Lichter entweder an oder aus, nicht, wie bei Blackjack, global aus oder auf den vorherigen Zustand:
Code: Alles auswählen
import time
class Switch(object):
def __init__(self, state=False, master=None):
self.state = state
self._master = master
def __str__(self):
return "Switch (%s)" % ['Off', 'On'][self.state]
def set_state(self, state):
self._state = state
self.state_change = time.time()
def get_state(self):
if self._master and (self._master.state_change > self.state_change):
self._state = self._master.state
return self._state
state = property(get_state, set_state)
def main():
master = Switch()
s1 = Switch(master=master)
s2 = Switch(master=master)
print master.state, s1.state, s2.state
s1.state = True
print master.state, s1.state, s2.state
master.state = False
print master.state, s1.state, s2.state
master.state = True
print master.state, s1.state, s2.state
if __name__ == '__main__':
main()
Gruß,
Manuel
Erstmal vielen Dank für die Hilfe, natürlich ist der Lichtschalter kein optimales Beispiel. Ich dachte ich kann mein Problem so einfacher formulieren.
In der Realität geht es darum während der Simulation einzelnen Zellen (FVM-Methode) einen Schalter geben um sehen zu können ob sie ihren Zustand schon berechnet haben. Dabei soll zu Beginn eines Rechenschrittes der Schalter bei allen Zellen auf einen Schlag auf 0 gesetzt werden. Sobald eine Zelle ihren Zustand berechnet hat soll der Schalter der einzelnen Zelle auf 1 gesetzt werden.
@BlackJack: Danke für die Mühe, es wird wohl etwas brauchen bis ich dein Beispiel ganz durchstiegen habe. So wie ich es verstehe hat jeder Schalter die Information des "Masterschalters" und die Information seines eigenen Schalters. Diese müssen nicht übereinstimmen. Am Ende des Beispiels geben alle Schalter "off" zurück, der Schalter von room_a steht aber noch auf true. Diese Umsetzung funktioniert sicherlich und ich werde es wohl auch so machen.
Meine Überlegung hinter der Frage war ob es eine Art "Datentyp" gibt der für die einzelnen Schalter gilt, aber global vom Master angesprochen werden kann. Dies würde bedeuten das durch das Betätigen des Master Schlaters auch der Schalter von room_a auf false springt.
Wie gesagt ist wohl eher akademisch.
In der Realität geht es darum während der Simulation einzelnen Zellen (FVM-Methode) einen Schalter geben um sehen zu können ob sie ihren Zustand schon berechnet haben. Dabei soll zu Beginn eines Rechenschrittes der Schalter bei allen Zellen auf einen Schlag auf 0 gesetzt werden. Sobald eine Zelle ihren Zustand berechnet hat soll der Schalter der einzelnen Zelle auf 1 gesetzt werden.
@BlackJack: Danke für die Mühe, es wird wohl etwas brauchen bis ich dein Beispiel ganz durchstiegen habe. So wie ich es verstehe hat jeder Schalter die Information des "Masterschalters" und die Information seines eigenen Schalters. Diese müssen nicht übereinstimmen. Am Ende des Beispiels geben alle Schalter "off" zurück, der Schalter von room_a steht aber noch auf true. Diese Umsetzung funktioniert sicherlich und ich werde es wohl auch so machen.
Meine Überlegung hinter der Frage war ob es eine Art "Datentyp" gibt der für die einzelnen Schalter gilt, aber global vom Master angesprochen werden kann. Dies würde bedeuten das durch das Betätigen des Master Schlaters auch der Schalter von room_a auf false springt.
Wie gesagt ist wohl eher akademisch.
Aber warum muss es denn ein extra Datentyp dafür sein? Warum macht du das nicht einfach durch eine Variable die du setzt? Manchmal finde ich die einfachsten Lösungen einfach am praktischstenLufia hat geschrieben: Meine Überlegung hinter der Frage war ob es eine Art "Datentyp" gibt der für die einzelnen Schalter gilt, aber global vom Master angesprochen werden kann. Dies würde bedeuten das durch das Betätigen des Master Schlaters auch der Schalter von room_a auf false springt.
Master = true/false
wäre doch eigentlich schon ausreichend für dein Problem, wenn ich das bis hierhin richtig verstanden habe.
- Hyperion
- Moderator
- Beiträge: 7478
- Registriert: Freitag 4. August 2006, 14:56
- Wohnort: Hamburg
- Kontaktdaten:
Ich danke Dir Ich glaube ich habs nun verstanden. Wenn ich das richtig sehe, fasst Du die getter und setter Funktionen der property nur aus Übersichtsgründen in einer übergeordneten Funktion zusammen?BlackJack hat geschrieben: ``@apply`` ist ja nur syntaktischer Zucker für folgende Zeile *nach* der ``def`` von `state`: ``state = apply(state)``. Und `apply()` ruft in dem Fall `state` einfach nur auf, also ``state = state()``. `state()` (also das alte) liefert ein `property`-Exemplar und das wird an `state` (neu) gebunden. Das war's auch schon.
Wie helduel es schon ansprach und umsetzte, bedarf es bei dieser Lösung mit dem Master-Object ja wohl eines Timestamps. Inwiefern ist mein konventioneller Ansatz da schlechter? "Besser" ist er ja, weil ich keine Zeitinformation benötige. Aber ich vermute es sprechen da andere Gründe dagegen, die ich vermutlich nicht durchschaue
@Lufia: Bei *der* Problembeschreibung brauchst Du einfach eine Schleife die bei jeder Zelle den "Schalter" auf 0 setzt. Anders geht's nicht.
Nochmal vielen lieben dank, ich habe jetzt alle 3 Beispiele getestet. Wobei ich beim ersten Zeile 12 verändern musste.
Jetzt muss ich mir noch das Visitor-Problem anschauen, bzw. generell Design-Patterns. Habe mir gerade das Buch von einem Kollegen ausgeliehen, leider in Java und auf englisch,... zu Hause habe ich auch ein Buch dazu herumliegen.
Es gibt noch so viel zu lernen,...
[Edit]
@BlackJack: Da ich eh schon eine Schleife über das Netz zum setzen der Anfangsbedingunen durchlaufe ist der Aufwand nciht sonderlich groß, ist halt nur nicht so elegant
Jetzt muss ich mir noch das Visitor-Problem anschauen, bzw. generell Design-Patterns. Habe mir gerade das Buch von einem Kollegen ausgeliehen, leider in Java und auf englisch,... zu Hause habe ich auch ein Buch dazu herumliegen.
Es gibt noch so viel zu lernen,...
[Edit]
@BlackJack: Da ich eh schon eine Schleife über das Netz zum setzen der Anfangsbedingunen durchlaufe ist der Aufwand nciht sonderlich groß, ist halt nur nicht so elegant