Seite 1 von 1

"Schalter - Objekt" programmieren

Verfasst: Freitag 26. September 2008, 11:41
von Lufia
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

Verfasst: Freitag 26. September 2008, 11:56
von Hyperion
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()

Verfasst: Freitag 26. September 2008, 11:57
von lunar
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.

Verfasst: Freitag 26. September 2008, 12:03
von Hyperion
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.
Hm ... ich dachte das wäre genau die Intention von Lufia? Ansonsten brauchste ja doch wieder eine Schleife um alle Schalter einzuschalten.

Verfasst: Freitag 26. September 2008, 12:15
von BlackJack
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

Verfasst: Freitag 26. September 2008, 12:19
von Hyperion
@BlackJack: Könntest Du uns "sterblichen" die Magie von Zeile 9 - 18 mal erklären? :-)

Verfasst: Freitag 26. September 2008, 12:27
von BlackJack
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.

Verfasst: Freitag 26. September 2008, 12:34
von Lonestar
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 :roll:

Verfasst: Freitag 26. September 2008, 12:44
von helduel
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:

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()
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

Verfasst: Freitag 26. September 2008, 12:49
von Lufia
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.

Verfasst: Freitag 26. September 2008, 13:06
von Lonestar
Lufia 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.
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 praktischsten

Master = true/false

wäre doch eigentlich schon ausreichend für dein Problem, wenn ich das bis hierhin richtig verstanden habe.

Verfasst: Freitag 26. September 2008, 13:20
von Hyperion
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.
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?

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 :-D

Verfasst: Freitag 26. September 2008, 13:37
von BlackJack
@Lufia: Bei *der* Problembeschreibung brauchst Du einfach eine Schleife die bei jeder Zelle den "Schalter" auf 0 setzt. Anders geht's nicht.

Verfasst: Freitag 26. September 2008, 13:39
von Lufia
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