Betrachten Sie Schalter (Einschaltknopf für Beleuchtung, Zielknopf auf jeder Etage des Aufzugs usw.) als primitives Modell mit Status und Verhalten. Der Schalter hat zwei Zustände, einen gedrückten Zustand "Ein" und einen nicht gedrückten Zustand "Aus". Auch das Verhalten des Schalters "switch ()" ändert sich je nach Status. Wenn es gedrückt wird, befindet es sich im nicht gedrückten Zustand "Aus", und wenn es nicht gedrückt wird, befindet es sich im gedrückten Zustand "Ein".
example1
class Switch:
def __init__(self, state="off"):
self.state = state
def switch(self):
if self.state == "on":
self.state = "off"
elif self.state == "off":
self.state = "on"
else:
# I wonder whether it should be ValueError().
raise RuntimeError(self.__class__.__name__ + " has an unexpected state: {}".format(self.state))
switch = Switch()
assert switch.state == "off"
switch.switch()
assert switch.state == "on"
switch.switch()
assert switch.state == "off"
switch.state = True
switch.switch()
-> RuntimeError: Switch has an unexpected state: True
Für die möglichen Werte (Zustände) von "Switch.state" müssen Sie sich die Implementierung von "Switch" ansehen. Die Verwendung von Aufzählungswerten zur Darstellung von Zuständen kann beispielsweise die Sichtbarkeit verbessern.
example2
from enum import Enum, auto
class SwitchState(Enum):
ON = auto()
OFF = auto()
class Switch:
def __init__(self, state=SwitchState.OFF):
self.state = state
def switch(self):
if self.state == SwitchState.ON:
self.state = SwitchState.OFF
elif self.state == SwitchState.OFF:
self.state = SwitchState.ON
else:
raise RuntimeError(self.__class__.__name__ + " has an unexpected state: {}".format(self.state))
switch = Switch(SwitchState.ON)
switch.switch()
switch = Switch("on") # warning: expected SwitchState type
Wenn der Standardwert des Konstruktorarguments "state" auf "SwitchState" gesetzt ist, wird eine Warnung für andere Werte als "SwitchState" ausgegeben. Unerwartete Werte wie "Ein" können jedoch "Switch.state" wie folgt zugewiesen werden.
switch.state = True
switch.switch() # RuntimeError: Switch has an unexpected state: True
Sie bemerken nicht, dass ein unerwarteter Wert zugewiesen wurde, bis switch ()
aufgerufen wurde. Daher ist es einfacher, einen TypeError zu senden, wenn "Switch.state" wie unten gezeigt ein unerwarteter Wert zugewiesen wird.
example2
class Switch:
def __init__(self, state=SwitchState.OFF):
self._state = state
def switch(self):
if self._state == SwitchState.ON:
self._state = SwitchState.OFF
elif self._state == SwitchState.OFF:
self._state = SwitchState.ON
else:
raise RuntimeError(self.__class__.__name__ + " has an unexpected state: {}".format(self._state))
@property
def state(self) -> SwitchState:
return self._state
@state.setter
def state(self, value: SwitchState):
if type(value) is not SwitchState:
raise TypeError(self.__class__.__name__ + ".state must be SwitchState, but get: {}".format(type(value)))
self._state = value
switch = Switch(SwitchState.ON)
switch.switch()
switch.state = True # TypeError: Switch.state must be SwitchState, but get: <class 'bool'>
Wenn Sie nicht möchten, dass der Status von "Switch" von außerhalb der Klasse geändert wird, können Sie in "Switch.state" keinen Wert festlegen.
class Switch:
def __init__(self, state=SwitchState.OFF):
self._state = state
def switch(self):
if self._state == SwitchState.ON:
self._state = SwitchState.OFF
elif self._state == SwitchState.OFF:
self._state = SwitchState.ON
else:
raise RuntimeError(self.__class__.__name__ + " has an unexpected state: {}".format(self._state))
@property
def state(self) -> SwitchState:
return self._state
switch = Switch(SwitchState.ON)
switch.switch()
switch.state = SwitchState.OFF # Property cannot be set
Wenn Sie den Status von "Switch" von außerhalb der Klasse ändern möchten, ist es besser, die Methoden "turn_on ()", "turn_off ()" für den Statusübergang bereitzustellen, als "Switch.state" an außerhalb der Klasse abzugeben. In manchen Fällen.
class Switch:
def __init__(self, state=SwitchState.OFF):
self._state = state
def switch(self):
if self._state == SwitchState.ON:
self.turn_off()
elif self._state == SwitchState.OFF:
self.turn_on()
else:
raise RuntimeError(self.__class__.__name__ + " has an unexpected state: {}".format(self._state))
@property
def state(self) -> SwitchState:
return self._state
def turn_on(self):
self._state = SwitchState.ON
def turn_off(self):
self._state = SwitchState.OFF
switch = Switch()
switch.turn_off()
assert switch.state == SwitchState.OFF
switch.switch()
assert switch.state == SwitchState.ON
Schließlich werden wir die Implementierung basierend auf dem Hinzufügen von Funktionen zu "Switch" später ändern. Bisher wurde es so implementiert, dass sich das Verhalten je nach Status ändert (die Verarbeitung der Methode unterscheidet sich je nach Status), es kann jedoch auch so implementiert werden, dass der Status durch den Unterschied im Verhalten ausgedrückt wird (der Status unterscheidet sich je nach Unterschied in der Verarbeitung). es kann.
from enum import Enum, auto
class SwitchState(Enum):
ON = auto()
OFF = auto()
class Switch:
def __init__(self, state=SwitchState.OFF):
self.switch = self.turn_on if state == SwitchState.OFF else self.turn_off
@property
def state(self) -> SwitchState:
return SwitchState.OFF if self.switch == self.turn_on else SwitchState.ON
def turn_on(self):
self.switch = self.turn_off
def turn_off(self):
self.switch = self.turn_on
switch = Switch(SwitchState.ON)
switch.switch()
assert switch.state == SwitchState.OFF
switch.switch()
assert switch.state == SwitchState.ON
Es gibt keinen Unterschied in der Funktionalität von "Switch", nur die Implementierung ist unterschiedlich.