Skip to content

Instantly share code, notes, and snippets.

@Drblessing
Created June 7, 2023 21:35
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save Drblessing/0a2701e0647448479993f9bbf327d7f6 to your computer and use it in GitHub Desktop.
Save Drblessing/0a2701e0647448479993f9bbf327d7f6 to your computer and use it in GitHub Desktop.
"""
Observer Design Pattern for Car objects when it starts.
"""
from __future__ import annotations
from abc import ABC, abstractmethod
from typing import List, Optional
class Subject(ABC):
@property
@abstractmethod
def is_running(self) -> bool:
pass
@abstractmethod
def startup_error(self) -> None:
pass
@abstractmethod
def attach(self, observer: Observer) -> None:
pass
@abstractmethod
def detach(self, observer: Observer) -> None:
pass
@abstractmethod
def notify(self) -> None:
pass
class Observer(ABC):
@abstractmethod
def update(self, subject: Subject) -> None:
pass
"""
Composition Design Pattern.
"""
import random
class Car(Subject):
@property
def is_running(self) -> bool:
return self._is_running
@is_running.setter
def is_running(self, value: bool) -> None:
print("Car: Starting" if value else "Car: Stopped")
self._is_running = value
self.notify()
def __init__(
self, engine: Engine, tires: List[Tire], fuel_tank: FuelTank, make: str
) -> None:
self._is_running = False
self._engine = engine
self._tires = tires
self._fuel_tank = fuel_tank
self._observers: List[Observer] = [engine, fuel_tank] + tires
self.make = make
def attach(self, observer: Observer) -> None:
self._observers.append(observer)
def detach(self, observer: Observer) -> None:
self._observers.remove(observer)
def notify(self) -> None:
for observer in self._observers:
observer.update(self)
def start_car(self) -> None:
self.is_running = True
def stop_car(self) -> None:
self.is_running = False
def startup_error(self) -> None:
print("Car: Error starting up...")
self.stop_car()
class Engine(Observer):
def __init__(self, horsepower: int) -> None:
self.horsepower = horsepower
def update(self, subject: Subject) -> None:
if subject.is_running:
print("Engine: started")
print("Vroooooooommmm!")
else:
print("Engine: stopped")
class Tire(Observer):
"""
The tire will throw an error 1/100 times when the car is started, simulating a flat tire.
Instead of an error, we will stop the car.
"""
def __init__(self) -> None:
self.flat = False
def update(self, subject: Subject) -> None:
if subject.is_running:
if random.randint(0, 100) == 0:
print(f"Tire: exploded!")
self.flat = True
subject.startup_error()
else:
print(f"Tire: is rolling!")
def fix(self) -> None:
self.flat = False
class FuelTank(Observer):
def __init__(self, capacity: float) -> None:
self.capacity = capacity
self.fuel = capacity
def update(self, subject: Subject) -> None:
if subject.is_running:
if self.fuel > 0:
print("FuelTank: started")
print("FuelTank: decreased fuel level")
self.fuel -= 0.5
else:
print("FuelTank: empty")
subject.startup_error()
def refuel(self) -> None:
self._fuel = self.capacity
print("FuelTank: refueled")
# Let's ride!
engine = Engine(horsepower=400)
tires = [Tire() for _ in range(4)]
fuel_tank = FuelTank(capacity=1)
ford = Car(engine, tires, fuel_tank, make="Ford")
ford.start_car()
ford.stop_car()
ford.start_car()
ford.stop_car()
ford.start_car()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment