Created
December 3, 2023 09:35
-
-
Save 270ajay/e6f6081cf79f7785e9555abe97ab225c to your computer and use it in GitHub Desktop.
Design Patterns: Taken from Derek Banas's Design Patterns Playlist on YouTube
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
from abc import ABC, abstractmethod | |
class EnemyShipBuilding(ABC): | |
@abstractmethod | |
def make_enemy_ship(self, type_of_ship: str) -> "EnemyShip": | |
pass | |
def order_the_ship(self, type_of_ship: str) -> "EnemyShip": | |
the_enemy_ship = self.make_enemy_ship(type_of_ship) | |
the_enemy_ship.make_ship() | |
the_enemy_ship.display_enemy_ship() | |
the_enemy_ship.follow_hero_ship() | |
the_enemy_ship.enemy_ship_shoots() | |
return the_enemy_ship | |
class UFOEnemyShipBuilding(EnemyShipBuilding): | |
def make_enemy_ship(self, type_of_ship: str) -> "EnemyShip": | |
if type_of_ship == "UFO": | |
ship_parts_factory = UFOEnemyShipFactory() | |
the_enemy_ship = UFOEnemyShip(ship_parts_factory) | |
the_enemy_ship.name = "UFO Grunt Ship" | |
elif type_of_ship == "UFO BOSS": | |
ship_parts_factory = UFOBossEnemyShipFactory() | |
the_enemy_ship = UFOBossEnemyShip(ship_parts_factory) | |
the_enemy_ship.name = "UFO Boss Ship" | |
else: | |
raise ValueError("type of ship must be UFO or UFO BOSS") | |
return the_enemy_ship | |
class ESWeapon(ABC): | |
@abstractmethod | |
def __str__(self) -> str: | |
pass | |
class ESEngine(ABC): | |
@abstractmethod | |
def __str__(self) -> str: | |
pass | |
class ESUFOGun(ESWeapon): | |
def __str__(self) -> str: | |
return "20 damage" | |
class ESUFOEngine(ESEngine): | |
def __str__(self) -> str: | |
return "1000 mph" | |
class ESUFOBossGun(ESWeapon): | |
def __str__(self) -> str: | |
return "40 damage" | |
class ESUFOBossEngine(ESEngine): | |
def __str__(self) -> str: | |
return "2000 mph" | |
class EnemyShipFactory(ABC): | |
@abstractmethod | |
def add_es_gun(self) -> "ESWeapon": | |
pass | |
@abstractmethod | |
def add_es_engine(self) -> "ESEngine": | |
pass | |
class UFOEnemyShipFactory(EnemyShipFactory): | |
def add_es_gun(self) -> "ESWeapon": | |
return ESUFOGun() | |
def add_es_engine(self) -> "ESEngine": | |
return ESUFOEngine() | |
class UFOBossEnemyShipFactory(EnemyShipFactory): | |
def add_es_gun(self) -> "ESWeapon": | |
return ESUFOBossGun() | |
def add_es_engine(self) -> "ESEngine": | |
return ESUFOBossEngine() | |
class EnemyShip(ABC): | |
def __init__(self): | |
self.name: str = "" | |
self.weapon: ESWeapon = None | |
self.engine: ESEngine = None | |
@abstractmethod | |
def make_ship(self) -> None: | |
pass | |
def __str__(self) -> str: | |
info_on_ship = f"The {self.name} has a top speed of {self.engine} and an attack power of {self.weapon}" | |
return info_on_ship | |
def follow_hero_ship(self) -> None: | |
print(f"{self.name} is following the hero at {self.engine}") | |
def display_enemy_ship(self) -> None: | |
print(f"{self.name} is on the screen") | |
def enemy_ship_shoots(self) -> None: | |
print(f"{self.name} attacks and does {self.weapon}") | |
class UFOEnemyShip(EnemyShip): | |
def __init__(self, ship_factory: EnemyShipFactory): | |
super().__init__() | |
self.ship_factory = ship_factory | |
def make_ship(self) -> None: | |
print(f"Making enemy ship {self.name}") | |
self.weapon = self.ship_factory.add_es_gun() | |
self.engine = self.ship_factory.add_es_engine() | |
class UFOBossEnemyShip(EnemyShip): | |
def __init__(self, ship_factory: EnemyShipFactory): | |
super().__init__() | |
self.ship_factory = ship_factory | |
def make_ship(self) -> None: | |
print(f"Making enemy ship {self.name}") | |
self.weapon = self.ship_factory.add_es_gun() | |
self.engine = self.ship_factory.add_es_engine() | |
class RocketEnemyShip(EnemyShip): | |
def __init__(self): | |
super().__init__() | |
self.name = "Rocket Enemy Ship" | |
self.amt_damage = 10.0 | |
class BigUFOEnemyShip(UFOEnemyShip): | |
def __init__(self): | |
super().__init__() | |
self.name = "Big UFO Enemy Ship" | |
self.amt_damage = 40.0 | |
def do_stuff_enemy(an_enemy_ship: EnemyShip) -> None: | |
an_enemy_ship.display_enemy_ship() | |
an_enemy_ship.follow_hero_ship() | |
an_enemy_ship.enemy_ship_shoots() | |
# Enemy ship factory | |
def make_enemy_ship(new_ship_type: str) -> EnemyShip: | |
if new_ship_type == "U": | |
return UFOEnemyShip() | |
elif new_ship_type == "R": | |
return RocketEnemyShip() | |
elif new_ship_type == "B": | |
return BigUFOEnemyShip() | |
else: | |
raise ValueError("Ship type can be U or R or B only") | |
if __name__ == "__main__": | |
make_ufos = UFOEnemyShipBuilding() | |
the_grunt = make_ufos.order_the_ship("UFO") | |
print(the_grunt, "\n") | |
the_boss = make_ufos.order_the_ship("UFO BOSS") | |
print(the_boss, "\n") |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import random | |
from abc import ABC, abstractmethod | |
class EnemyAttacker(ABC): | |
@abstractmethod | |
def fire_weapon(self) -> None: | |
pass | |
@abstractmethod | |
def drive_forward(self) -> None: | |
pass | |
@abstractmethod | |
def assign_driver(self, driver_name: str) -> None: | |
pass | |
class EnemyTank(EnemyAttacker): | |
def fire_weapon(self) -> None: | |
attack_damage = random.randint(1, 11) | |
print(f"Enemy tank does {attack_damage} damage") | |
def drive_forward(self) -> None: | |
movement = random.randint(1, 6) | |
print(f"Enemy tank moves {movement} spaces") | |
def assign_driver(self, driver_name: str) -> None: | |
print(f"{driver_name} is driving the tank") | |
class EnemyRobot: | |
def smash_with_hands(self) -> None: | |
attack_damage = random.randint(1, 11) | |
print(f"Enemy robot cause {attack_damage} damage with its hands") | |
def walk_forward(self) -> None: | |
movement = random.randint(1, 6) | |
print(f"Enemy robot walks forward {movement} spaces") | |
def react_to_human(self, driver_name: str) -> None: | |
print(f"Enemy robot tramps on {driver_name}") | |
class EnemyRobotAdapter(EnemyAttacker): | |
def __init__(self, new_robot: EnemyRobot): | |
self.the_robot: EnemyRobot = new_robot | |
def fire_weapon(self) -> None: | |
self.the_robot.smash_with_hands() | |
def drive_forward(self) -> None: | |
self.the_robot.walk_forward() | |
def assign_driver(self, driver_name: str) -> None: | |
self.the_robot.react_to_human(driver_name) | |
if __name__ == "__main__": | |
random.seed(10) | |
rx7_tank = EnemyTank() | |
fred_the_robot = EnemyRobot() | |
robot_adapter = EnemyRobotAdapter(fred_the_robot) | |
print("The Robot") | |
fred_the_robot.react_to_human("Paul") | |
fred_the_robot.walk_forward() | |
fred_the_robot.smash_with_hands() | |
print() | |
print("The Enemy Tank") | |
rx7_tank.assign_driver("Frank") | |
rx7_tank.drive_forward() | |
rx7_tank.fire_weapon() | |
print() | |
print("The Robot With Adapter") | |
robot_adapter.assign_driver("Mark") | |
robot_adapter.drive_forward() | |
robot_adapter.fire_weapon() |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
from abc import ABC, abstractmethod | |
class EntertainmentDevice(ABC): | |
def __init__(self): | |
self.device_state: int = 0 | |
self.max_setting: int = 0 | |
self.volume_level: int = 0 | |
@abstractmethod | |
def button_five_pressed(self) -> None: | |
pass | |
@abstractmethod | |
def button_six_pressed(self) -> None: | |
pass | |
def device_feedback(self) -> None: | |
if self.device_state > self.max_setting or self.device_state < 0: | |
self.device_state = 0 | |
print("On", self.device_state) | |
def button_seven_pressed(self) -> None: | |
self.volume_level += 1 | |
print("Volume at:", self.volume_level) | |
def button_eight_pressed(self) -> None: | |
self.volume_level -= 1 | |
print("Volume at:", self.volume_level) | |
class TVDevice(EntertainmentDevice): | |
def __init__(self, new_device_state: int, new_max_setting: int): | |
super().__init__() | |
self.device_state = new_device_state | |
self.max_setting = new_max_setting | |
def button_five_pressed(self) -> None: | |
print("Channel Down") | |
self.device_state -= 1 | |
def button_six_pressed(self) -> None: | |
print("Channel Up") | |
self.device_state += 1 | |
class RemoteButton(ABC): | |
def __init__(self, new_entertainment_device: EntertainmentDevice): | |
self.the_device: EntertainmentDevice = new_entertainment_device | |
def button_five_pressed(self) -> None: | |
self.the_device.button_five_pressed() | |
def button_six_pressed(self) -> None: | |
self.the_device.button_six_pressed() | |
def device_feedback(self) -> None: | |
self.the_device.device_feedback() | |
@abstractmethod | |
def button_nine_pressed(self) -> None: | |
pass | |
class TVRemoteMute(RemoteButton): | |
def __init__(self, new_device: EntertainmentDevice): | |
super().__init__(new_device) | |
def button_nine_pressed(self) -> None: | |
print("TV was muted") | |
class TVRemotePause(RemoteButton): | |
def __init__(self, new_device: EntertainmentDevice): | |
super().__init__(new_device) | |
def button_nine_pressed(self) -> None: | |
print("TV was paused") | |
if __name__ == "__main__": | |
the_tv = TVRemoteMute(TVDevice(1, 200)) | |
the_tv2 = TVRemotePause(TVDevice(1, 200)) | |
print(f"Test TV with mute") | |
the_tv.button_five_pressed() | |
the_tv.button_six_pressed() | |
the_tv.button_nine_pressed() | |
print(f"\nTest TV with pause") | |
the_tv2.button_five_pressed() | |
the_tv2.button_six_pressed() | |
the_tv2.button_six_pressed() | |
the_tv2.button_six_pressed() | |
the_tv2.button_six_pressed() | |
the_tv2.button_nine_pressed() | |
the_tv2.device_feedback() |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
from abc import ABC, abstractmethod | |
class RobotPlan(ABC): | |
@abstractmethod | |
def set_robot_head(self, head: str) -> None: | |
pass | |
@abstractmethod | |
def set_robot_torso(self, torso: str) -> None: | |
pass | |
@abstractmethod | |
def set_robot_arms(self, arms: str) -> None: | |
pass | |
@abstractmethod | |
def set_robot_legs(self, legs: str) -> None: | |
pass | |
class Robot(RobotPlan): | |
def __init__(self): | |
self.robot_head: str = "" | |
self.robot_torso: str = "" | |
self.robot_arms: str = "" | |
self.robot_legs: str = "" | |
def set_robot_head(self, head: str) -> None: | |
self.robot_head = head | |
def set_robot_torso(self, torso: str) -> None: | |
self.robot_torso = torso | |
def set_robot_arms(self, arms: str) -> None: | |
self.robot_arms = arms | |
def set_robot_legs(self, legs: str) -> None: | |
self.robot_legs = legs | |
class RobotBuilder(ABC): | |
@abstractmethod | |
def build_robot_head(self) -> None: | |
pass | |
@abstractmethod | |
def build_robot_torso(self) -> None: | |
pass | |
@abstractmethod | |
def build_robot_arms(self) -> None: | |
pass | |
@abstractmethod | |
def build_robot_legs(self) -> None: | |
pass | |
@abstractmethod | |
def get_robot(self) -> Robot: | |
pass | |
class OldRobotBuilder(RobotBuilder): | |
def __init__(self): | |
self.robot: Robot = Robot() | |
def build_robot_head(self) -> None: | |
self.robot.set_robot_head("Tin Head") | |
def build_robot_torso(self) -> None: | |
self.robot.set_robot_torso("Tin Torso") | |
def build_robot_arms(self) -> None: | |
self.robot.set_robot_arms("Blowtorch Arms") | |
def build_robot_legs(self) -> None: | |
self.robot.set_robot_legs("Roller Skates") | |
def get_robot(self) -> Robot: | |
return self.robot | |
class RobotEngineer: | |
def __init__(self, robot_builder: RobotBuilder): | |
self.robot_builder: RobotBuilder = robot_builder | |
def get_robot(self) -> Robot: | |
return self.robot_builder.get_robot() | |
def make_robot(self) -> None: | |
self.robot_builder.build_robot_head() | |
self.robot_builder.build_robot_torso() | |
self.robot_builder.build_robot_arms() | |
self.robot_builder.build_robot_legs() | |
if __name__ == "__main__": | |
old_style_robot = OldRobotBuilder() | |
robot_engineer = RobotEngineer(old_style_robot) | |
robot_engineer.make_robot() | |
first_robot = robot_engineer.get_robot() | |
print(f"Robot Built") | |
print(f"Robot Head Type: {first_robot.robot_head}") | |
print(f"Robot Torso Type: {first_robot.robot_torso}") | |
print(f"Robot Arm Type: {first_robot.robot_arms}") | |
print(f"Robot Leg Type: {first_robot.robot_legs}") |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
from abc import ABC, abstractmethod | |
class Chain(ABC): | |
@abstractmethod | |
def set_next_chain(self, next_chain: "Chain") -> None: | |
pass | |
@abstractmethod | |
def calculate(self, request: "Numbers") -> None: | |
pass | |
class Numbers: | |
def __init__(self, number1: int, number2: int, calc_wanted: str): | |
self.number1: int = number1 | |
self.number2: int = number2 | |
self.calculation_wanted: str = calc_wanted | |
class AddNumbers(Chain): | |
def __init__(self): | |
self.next_in_chain: Chain = None | |
def set_next_chain(self, next_chain: "Chain") -> None: | |
self.next_in_chain = next_chain | |
def calculate(self, request: "Numbers") -> None: | |
if request.calculation_wanted == "add": | |
print( | |
f"{request.number1} + {request.number2} = {request.number1 + request.number2}" | |
) | |
else: | |
self.next_in_chain.calculate(request) | |
class SubtractNumbers(Chain): | |
def __init__(self): | |
self.next_in_chain: Chain = None | |
def set_next_chain(self, next_chain: "Chain") -> None: | |
self.next_in_chain = next_chain | |
def calculate(self, request: "Numbers") -> None: | |
if request.calculation_wanted == "sub": | |
print( | |
f"{request.number1} - {request.number2} = {request.number1 - request.number2}" | |
) | |
else: | |
self.next_in_chain.calculate(request) | |
class MultiplyNumbers(Chain): | |
def __init__(self): | |
self.next_in_chain: Chain = None | |
def set_next_chain(self, next_chain: "Chain") -> None: | |
self.next_in_chain = next_chain | |
def calculate(self, request: "Numbers") -> None: | |
if request.calculation_wanted == "mult": | |
print( | |
f"{request.number1} * {request.number2} = {request.number1 * request.number2}" | |
) | |
else: | |
self.next_in_chain.calculate(request) | |
class DivideNumbers(Chain): | |
def __init__(self): | |
self.next_in_chain: Chain = None | |
def set_next_chain(self, next_chain: "Chain") -> None: | |
self.next_in_chain = next_chain | |
def calculate(self, request: "Numbers") -> None: | |
if request.calculation_wanted == "div": | |
print( | |
f"{request.number1} / {request.number2} = {request.number1 / request.number2}" | |
) | |
else: | |
print("Only works for add, sub, mult, and div") | |
if __name__ == "__main__": | |
chain_calc1 = AddNumbers() | |
chain_calc2 = SubtractNumbers() | |
chain_calc3 = MultiplyNumbers() | |
chain_calc4 = DivideNumbers() | |
chain_calc1.set_next_chain(chain_calc2) | |
chain_calc2.set_next_chain(chain_calc3) | |
chain_calc3.set_next_chain(chain_calc4) | |
request = Numbers(4, 2, "mult") | |
chain_calc1.calculate(request) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
from abc import ABC, abstractmethod | |
class ElectronicDevice(ABC): | |
@abstractmethod | |
def on(self) -> None: | |
pass | |
@abstractmethod | |
def off(self) -> None: | |
pass | |
@abstractmethod | |
def volume_up(self) -> None: | |
pass | |
@abstractmethod | |
def volume_down(self) -> None: | |
pass | |
class Television(ElectronicDevice): | |
def __init__(self): | |
self.volume = 0 | |
def on(self) -> None: | |
print("TV is on") | |
def off(self) -> None: | |
print("TV is off") | |
def volume_up(self) -> None: | |
self.volume += 1 | |
print("TV Volume is at", self.volume) | |
def volume_down(self) -> None: | |
self.volume -= 1 | |
print("TV Volume is at", self.volume) | |
class Radio(ElectronicDevice): | |
def __init__(self): | |
self.volume = 0 | |
def on(self) -> None: | |
print("Radio is on") | |
def off(self) -> None: | |
print("Radio is off") | |
def volume_up(self) -> None: | |
self.volume += 1 | |
print("Radio Volume is at", self.volume) | |
def volume_down(self) -> None: | |
self.volume -= 1 | |
print("Radio Volume is at", self.volume) | |
class Command(ABC): | |
@abstractmethod | |
def execute(self) -> None: | |
pass | |
@abstractmethod | |
def undo(self) -> None: | |
pass | |
class TurnTVOn(Command): | |
def __init__(self, new_device: ElectronicDevice): | |
self.the_device: ElectronicDevice = new_device | |
def execute(self) -> None: | |
self.the_device.on() | |
def undo(self) -> None: | |
self.the_device.off() | |
class TurnTVOff(Command): | |
def __init__(self, new_device: ElectronicDevice): | |
self.the_device: ElectronicDevice = new_device | |
def execute(self) -> None: | |
self.the_device.off() | |
def undo(self) -> None: | |
self.the_device.on() | |
class TurnTVUp(Command): | |
def __init__(self, new_device: ElectronicDevice): | |
self.the_device: ElectronicDevice = new_device | |
def execute(self) -> None: | |
self.the_device.volume_up() | |
def undo(self) -> None: | |
self.the_device.volume_down() | |
class DeviceButton: | |
def __init__(self, new_command: Command): | |
self.the_command: Command = new_command | |
def press(self) -> None: | |
self.the_command.execute() | |
def press_undo(self) -> None: | |
self.the_command.undo() | |
class TurnItAllOff(Command): | |
def __init__(self, new_devices: list[ElectronicDevice]): | |
self.the_devices: list[ElectronicDevice] = new_devices | |
def execute(self) -> None: | |
for device in self.the_devices: | |
device.off() | |
def undo(self) -> None: | |
for device in self.the_devices: | |
device.on() | |
if __name__ == "__main__": | |
new_device = Television() | |
on_command = TurnTVOn(new_device) | |
on_pressed = DeviceButton(on_command) | |
on_pressed.press() | |
off_command = TurnTVOff(new_device) | |
on_pressed = DeviceButton(off_command) | |
on_pressed.press() | |
vol_up_command = TurnTVUp(new_device) | |
on_pressed = DeviceButton(vol_up_command) | |
on_pressed.press() | |
on_pressed.press() | |
on_pressed.press() | |
turn_off_devices = TurnItAllOff([Television(), Radio()]) | |
turn_them_off = DeviceButton(turn_off_devices) | |
turn_them_off.press() | |
turn_them_off.press_undo() |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
from abc import ABC | |
class SongComponent(ABC): | |
def add(self, new_song_component: "SongComponent") -> None: | |
raise NotImplementedError | |
def remove(self, new_song_component: "SongComponent") -> None: | |
raise NotImplementedError | |
def get(self, component_index: int) -> "SongComponent": | |
raise NotImplementedError | |
def get_song_name(self) -> str: | |
raise NotImplementedError | |
def get_band_name(self) -> str: | |
raise NotImplementedError | |
def get_release_year(self) -> int: | |
raise NotImplementedError | |
def display_song_info(self) -> None: | |
raise NotImplementedError | |
class SongGroup(SongComponent): | |
def __init__(self, new_group_name: str, new_group_description: str): | |
self.song_components: list[SongComponent] = [] | |
self.group_name: str = new_group_name | |
self.group_description: str = new_group_description | |
def add(self, new_song_component: "SongComponent") -> None: | |
self.song_components.append(new_song_component) | |
def remove(self, new_song_component: "SongComponent") -> None: | |
self.song_components.remove(new_song_component) | |
def get(self, component_index: int) -> "SongComponent": | |
return self.song_components[component_index] | |
def display_song_info(self) -> None: | |
print(f"{self.group_name} {self.group_description}\n") | |
for song_component in self.song_components: | |
song_component.display_song_info() | |
class Song(SongComponent): | |
def __init__(self, song_name: str, band_name: str, release_year: int): | |
self.song_name: str = song_name | |
self.band_name: str = band_name | |
self.release_year: int = release_year | |
def get_song_name(self) -> str: | |
return self.song_name | |
def get_band_name(self) -> str: | |
return self.band_name | |
def get_release_year(self) -> int: | |
return self.release_year | |
def display_song_info(self) -> None: | |
print( | |
f"{self.song_name} was recorded by {self.band_name} in {self.release_year}" | |
) | |
class DiskJockey: | |
def __init__(self, new_songs: SongComponent): | |
self.songs: SongComponent = new_songs | |
def get_song_list(self) -> None: | |
self.songs.display_song_info() | |
if __name__ == "__main__": | |
industrial_music = SongGroup("Industrial", "Transgressive and provocative themes") | |
heavy_metal_music = SongGroup("\nHeavy Metal", "Rock developed in late 1960s") | |
dub_step_music = SongGroup("\nDubstep", "Electronic dance music") | |
every_song = SongGroup("Song List", "Every song available") | |
every_song.add(industrial_music) | |
industrial_music.add(Song("Head like a hole", "NIN", 1990)) | |
industrial_music.add(Song("Headhunter", "Front 242", 1988)) | |
industrial_music.add(dub_step_music) | |
dub_step_music.add(Song("Centipede", "Knife Party", 2012)) | |
dub_step_music.add(Song("Tetris", "Doctor P", 2011)) | |
every_song.add(heavy_metal_music) | |
heavy_metal_music.add(Song("War Pigs", "Black Sabath", 1970)) | |
heavy_metal_music.add(Song("Ace of Spades", "Motorhead", 1980)) | |
crazy_larry = DiskJockey(every_song) | |
crazy_larry.get_song_list() |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
from abc import ABC, abstractmethod | |
class Pizza(ABC): | |
@abstractmethod | |
def set_description(self, new_description: str) -> None: | |
pass | |
@abstractmethod | |
def get_description(self) -> str: | |
pass | |
@abstractmethod | |
def get_cost(self) -> float: | |
pass | |
class ThreeCheesePizza(Pizza): | |
def set_description(self, new_description: str) -> None: | |
pass | |
def get_description(self) -> str: | |
return "Mozzarella, Fontina, Parmesan, Cheese Pizza" | |
def get_cost(self) -> float: | |
return 10.00 | |
# ------------------- New code | |
class PizzaNew(ABC): | |
@abstractmethod | |
def get_description(self) -> str: | |
pass | |
@abstractmethod | |
def get_cost(self) -> float: | |
pass | |
class PlainPizza(PizzaNew): | |
def __init__(self): | |
print("Adding Dough") | |
def get_description(self) -> str: | |
return "Thin Dough" | |
def get_cost(self) -> float: | |
return 4.00 | |
class ToppingDecorator(PizzaNew): | |
def __init__(self, new_pizza: PizzaNew): | |
self.temp_pizza: PizzaNew = new_pizza | |
def get_description(self) -> str: | |
return self.temp_pizza.get_description() | |
def get_cost(self) -> float: | |
return self.temp_pizza.get_cost() | |
class Mozzarella(ToppingDecorator): | |
def __init__(self, new_pizza: PizzaNew): | |
super().__init__(new_pizza) | |
print("Adding Moz") | |
def get_description(self) -> str: | |
return self.temp_pizza.get_description() + ", Mozzarella" | |
def get_cost(self) -> float: | |
return self.temp_pizza.get_cost() + 0.50 | |
class TomatoSauce(ToppingDecorator): | |
def __init__(self, new_pizza: PizzaNew): | |
super().__init__(new_pizza) | |
print("Adding Sauce") | |
def get_description(self) -> str: | |
return self.temp_pizza.get_description() + ", Tomato Sauce" | |
def get_cost(self) -> float: | |
return self.temp_pizza.get_cost() + 0.35 | |
if __name__ == "__main__": | |
# old code | |
three_cheese_pizza = ThreeCheesePizza() | |
print("Ingredients:", three_cheese_pizza.get_description()) | |
print("Price:", three_cheese_pizza.get_cost()) | |
print() | |
# new code | |
basic_pizza = TomatoSauce(Mozzarella(PlainPizza())) | |
print("Ingredients:", basic_pizza.get_description()) | |
print("Price:", basic_pizza.get_cost()) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
class WelcomeToBank: | |
def __init__(self): | |
print("Welcome to ABC Bank") | |
print("We are happy to give you your money if we can find it\n") | |
class AccountNumberCheck: | |
def __init__(self): | |
self._account_number = 12345678 | |
def account_active(self, account_number_to_check: int) -> bool: | |
return account_number_to_check == self._account_number | |
class SecurityCodeCheck: | |
def __init__(self): | |
self._security_code = 1234 | |
def is_code_correct(self, security_code_to_check: int) -> bool: | |
return security_code_to_check == self._security_code | |
class FundsCheck: | |
def __init__(self): | |
self._cash_in_account = 1000.00 | |
def decrease_cash_in_account(self, cash_withdrawn: float) -> None: | |
self._cash_in_account -= cash_withdrawn | |
def increase_cash_in_account(self, cash_deposited: float) -> None: | |
self._cash_in_account += cash_deposited | |
def have_enough_money(self, cash_to_withdraw: float) -> bool: | |
if cash_to_withdraw > self._cash_in_account: | |
print("Error: You don't have enough money") | |
print("Current Balance:", self._cash_in_account) | |
return False | |
self.decrease_cash_in_account(cash_to_withdraw) | |
print("Withdrawal Complete: Current balance is", self._cash_in_account) | |
return True | |
def make_deposit(self, cash_to_deposit: float) -> None: | |
self.increase_cash_in_account(cash_to_deposit) | |
print("Deposit Complete: Current balance is", self._cash_in_account) | |
class BankAccountFacade: | |
def __init__(self, account_number: int, security_code: int): | |
self.account_number: int = account_number | |
self.security_code: int = security_code | |
self.account_checker: AccountNumberCheck = AccountNumberCheck() | |
self.code_checker: SecurityCodeCheck = SecurityCodeCheck() | |
self.fund_checker: FundsCheck = FundsCheck() | |
self.bank_welcome: WelcomeToBank = WelcomeToBank() | |
def withdraw_cash(self, cash_to_get: float) -> None: | |
if ( | |
self.account_checker.account_active(self.account_number) | |
and self.code_checker.is_code_correct(self.security_code) | |
and self.fund_checker.have_enough_money(cash_to_get) | |
): | |
print("Transaction Complete\n") | |
else: | |
print("Transaction Failed\n") | |
def deposit_cash(self, cash_to_deposit: float) -> None: | |
if self.account_checker.account_active( | |
self.account_number | |
) and self.code_checker.is_code_correct(self.security_code): | |
self.fund_checker.make_deposit(cash_to_deposit) | |
print("Transaction Complete\n") | |
else: | |
print("Transaction Failed\n") | |
if __name__ == "__main__": | |
accessing_bank = BankAccountFacade(12345678, 1234) | |
accessing_bank.withdraw_cash(50.00) | |
accessing_bank.withdraw_cash(900.00) | |
accessing_bank.deposit_cash(200.00) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
from abc import ABC | |
class EnemyShip(ABC): | |
def __init__(self): | |
self.name: str = "" | |
self.amt_damage: float = 0.0 | |
def follow_hero_ship(self) -> None: | |
print(f"{self.name} is following the hero") | |
def display_enemy_ship(self) -> None: | |
print(f"{self.name} is on the screen") | |
def enemy_ship_shoots(self) -> None: | |
print(f"{self.name} attacks and does {self.amt_damage}") | |
class UFOEnemyShip(EnemyShip): | |
def __init__(self): | |
super().__init__() | |
self.name = "UFO Enemy Ship" | |
self.amt_damage = 20.0 | |
class RocketEnemyShip(EnemyShip): | |
def __init__(self): | |
super().__init__() | |
self.name = "Rocket Enemy Ship" | |
self.amt_damage = 10.0 | |
class BigUFOEnemyShip(UFOEnemyShip): | |
def __init__(self): | |
super().__init__() | |
self.name = "Big UFO Enemy Ship" | |
self.amt_damage = 40.0 | |
def do_stuff_enemy(an_enemy_ship: EnemyShip) -> None: | |
an_enemy_ship.display_enemy_ship() | |
an_enemy_ship.follow_hero_ship() | |
an_enemy_ship.enemy_ship_shoots() | |
# Enemy ship factory | |
def make_enemy_ship(new_ship_type: str) -> EnemyShip: | |
if new_ship_type == "U": | |
return UFOEnemyShip() | |
elif new_ship_type == "R": | |
return RocketEnemyShip() | |
elif new_ship_type == "B": | |
return BigUFOEnemyShip() | |
else: | |
raise ValueError("Ship type can be U or R or B only") | |
if __name__ == "__main__": | |
# old code | |
enemy_ship_option = input("What type of ship? (U / R) ") | |
if enemy_ship_option == "U": | |
the_enemy = UFOEnemyShip() | |
elif enemy_ship_option == "R": | |
the_enemy = RocketEnemyShip() | |
else: | |
raise ValueError("Only U or R is accepted") | |
do_stuff_enemy(the_enemy) | |
print() | |
# new code | |
enemy_ship_option = input("What type of ship? (U / R / B) ") | |
the_enemy = make_enemy_ship(enemy_ship_option) | |
do_stuff_enemy(the_enemy) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
from abc import ABC, abstractmethod | |
class SongInfo: | |
def __init__(self, new_song_name: str, new_band_name: str, new_year_released: int): | |
self.song_name: str = new_song_name | |
self.band_name: str = new_band_name | |
self.year_released: int = new_year_released | |
class SongIterator(ABC): | |
@abstractmethod | |
def __iter__(self): | |
pass | |
class SongsOfThe70s(SongIterator): | |
def __init__(self): | |
self.best_songs: list[SongInfo] = [] | |
self.add_song("Imagine", "John Lennon", 1971) | |
self.add_song("American Pie", "Don McLean", 1971) | |
self.add_song("I Will Survice", "Gloria Gaynor", 1979) | |
def add_song(self, song_name: str, band_name: str, year_released: int) -> None: | |
self.best_songs.append(SongInfo(song_name, band_name, year_released)) | |
# od code | |
def get_best_songs(self) -> list[SongInfo]: | |
return self.best_songs | |
def __iter__(self): | |
return iter(self.best_songs) | |
class SongsOfThe80s(SongIterator): | |
def __init__(self): | |
self.best_songs: list[SongInfo] = [] | |
self.add_song("Roam", "B52s", 1989) | |
self.add_song("Cruel Summer", "Bananarama", 1984) | |
self.add_song("Head Over Heels", "Tears For Fears", 1985) | |
def add_song(self, song_name: str, band_name: str, year_released: int) -> None: | |
self.best_songs.append(SongInfo(song_name, band_name, year_released)) | |
# old code | |
def get_best_songs(self) -> list[SongInfo]: | |
return self.best_songs | |
def __iter__(self): | |
return iter(self.best_songs) | |
class SongsOfThe90s(SongIterator): | |
def __init__(self): | |
self.best_songs: dict[int, SongInfo] = {} | |
self.hash_key = 0 | |
self.add_song("Losing My Religion", "REM", 1991) | |
self.add_song("Creep", "Radiohead", 1993) | |
self.add_song("Walk on the Ocean", "Toad the Wet Sprocket", 1991) | |
def add_song(self, song_name: str, band_name: str, year_released: int) -> None: | |
self.best_songs[self.hash_key] = SongInfo(song_name, band_name, year_released) | |
self.hash_key += 1 | |
# old code | |
def get_best_songs(self) -> dict[int, SongInfo]: | |
return self.best_songs | |
def __iter__(self): | |
return iter(self.best_songs.values()) | |
class DiscJockey: | |
def __init__( | |
self, | |
songs_70s: SongsOfThe70s, | |
songs_80s: SongsOfThe80s, | |
songs_90s: SongsOfThe90s, | |
): | |
self.songs_70s: SongsOfThe70s = songs_70s | |
self.songs_80s: SongsOfThe80s = songs_80s | |
self.songs_90s: SongsOfThe90s = songs_90s | |
def show_the_songs(self) -> None: | |
songs_70s_list = self.songs_70s.get_best_songs() | |
print("\nSongs of the 70s") | |
for song in songs_70s_list: | |
print(song.song_name) | |
print(song.band_name) | |
print(song.year_released) | |
songs_80s_list = self.songs_80s.get_best_songs() | |
print("\nSongs of the 80s") | |
for song in songs_80s_list: | |
print(song.song_name) | |
print(song.band_name) | |
print(song.year_released) | |
songs_90s_dict = self.songs_90s.get_best_songs() | |
print("\nSongs of the 90s") | |
for song in songs_90s_dict.values(): | |
print(song.song_name) | |
print(song.band_name) | |
print(song.year_released) | |
class DiscJockeyNew: | |
def __init__( | |
self, songs_70s: SongIterator, songs_80s: SongIterator, songs_90s: SongIterator | |
): | |
self.iter_songs_70s: SongIterator = songs_70s | |
self.iter_songs_80s: SongIterator = songs_80s | |
self.iter_songs_90s: SongIterator = songs_90s | |
def show_the_songs2(self) -> None: | |
print("\nSongs of the 70s") | |
self._print_the_songs(self.iter_songs_70s) | |
print("\nSongs of the 80s") | |
self._print_the_songs(self.iter_songs_80s) | |
print("\nSongs of the 90s") | |
self._print_the_songs(self.iter_songs_90s) | |
def _print_the_songs(self, song_iterator: SongIterator) -> None: | |
for song in song_iterator: | |
print(song.song_name) | |
print(song.band_name) | |
print(song.year_released) | |
if __name__ == "__main__": | |
songs_70s = SongsOfThe70s() | |
songs_80s = SongsOfThe80s() | |
songs_90s = SongsOfThe90s() | |
# old code | |
mad_mike = DiscJockey(songs_70s, songs_80s, songs_90s) | |
mad_mike.show_the_songs() | |
# new code | |
mad_mike2 = DiscJockeyNew(songs_70s, songs_80s, songs_90s) | |
mad_mike2.show_the_songs2() |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
from abc import ABC, abstractmethod | |
class StockOffer: | |
def __init__(self, num_shares: int, stock: str, coll_code: int): | |
self.stock_shares: int = num_shares | |
self.stock_symbol: str = stock | |
self.colleague_code: int = coll_code | |
class Colleague(ABC): | |
def __init__(self, mediator: "Mediator"): | |
self.mediator: "Mediator" = mediator | |
self.colleague_code: int = 0 | |
self.mediator.add_colleague(self) | |
def sale_offer(self, stock: str, shares: int) -> None: | |
self.mediator.sale_offer(stock, shares, self.colleague_code) | |
def buy_offer(self, stock: str, shares: int) -> None: | |
self.mediator.buy_offer(stock, shares, self.colleague_code) | |
def set_colleague_code(self, coll_code: int) -> None: | |
self.colleague_code = coll_code | |
class GormanSlacks(Colleague): | |
def __init__(self, mediator: "Mediator"): | |
super().__init__(mediator) | |
print("Gorman Slacks signed up for the exchange\n") | |
class JTPoorman(Colleague): | |
def __init__(self, mediator: "Mediator"): | |
super().__init__(mediator) | |
print("JT Poorman signed up for the exchange\n") | |
class Mediator(ABC): | |
@abstractmethod | |
def sale_offer(self, stock: str, shares: int, coll_code: int) -> None: | |
pass | |
@abstractmethod | |
def buy_offer(self, stock: str, shares: int, coll_code: int) -> None: | |
pass | |
@abstractmethod | |
def add_colleague(self, colleague: "Colleague") -> None: | |
pass | |
class StockMediator(Mediator): | |
def __init__(self): | |
self.colleagues: list[Colleague] = [] | |
self.stock_buy_offers: list[StockOffer] = [] | |
self.stock_sell_offers: list[StockOffer] = [] | |
self.colleague_codes: int = 0 | |
def add_colleague(self, colleague: "Colleague") -> None: | |
self.colleagues.append(colleague) | |
self.colleague_codes += 1 | |
colleague.set_colleague_code(self.colleague_codes) | |
def sale_offer(self, stock: str, shares: int, coll_code: int) -> None: | |
stock_sold = False | |
for offer in self.stock_buy_offers: | |
if offer.stock_symbol == stock and offer.stock_shares == shares: | |
print( | |
f"{shares} shares of {stock} sold to colleague code {offer.colleague_code}" | |
) | |
self.stock_buy_offers.remove(offer) | |
stock_sold = True | |
break | |
if not stock_sold: | |
print(f"{shares} shares of {stock} added to inventory") | |
new_offering = StockOffer(shares, stock, coll_code) | |
self.stock_sell_offers.append(new_offering) | |
def buy_offer(self, stock: str, shares: int, coll_code: int) -> None: | |
stock_bought = False | |
for offer in self.stock_sell_offers: | |
if offer.stock_symbol == stock and offer.stock_shares == shares: | |
print( | |
f"{shares} shares of {stock} bought by colleague code {offer.colleague_code}" | |
) | |
self.stock_sell_offers.remove(offer) | |
stock_bought = True | |
break | |
if not stock_bought: | |
print(f"{shares} shares of {stock} added to inventory") | |
new_offering = StockOffer(shares, stock, coll_code) | |
self.stock_buy_offers.append(new_offering) | |
def get_stock_offerings(self) -> None: | |
print("\nStocks for sale") | |
for offer in self.stock_sell_offers: | |
print(f"{offer.stock_shares} of {offer.stock_symbol}") | |
print("\nStocks Buy offers") | |
for offer in self.stock_buy_offers: | |
print(f"{offer.stock_shares} of {offer.stock_symbol}") | |
if __name__ == "__main__": | |
nyse = StockMediator() | |
broker = GormanSlacks(nyse) | |
broker2 = JTPoorman(nyse) | |
broker.sale_offer("MSFT", 100) | |
broker2.sale_offer("GOOG", 50) | |
broker.buy_offer("MSFT", 100) | |
broker2.sale_offer("NRG", 10) | |
broker.buy_offer("NRG", 10) | |
nyse.get_stock_offerings() |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
class Memento: | |
def __init__(self, article_save: str): | |
self.article: str = article_save | |
class Originator: | |
def __init__(self): | |
self.article: str = "" | |
def store_in_memento(self, article: str) -> "Memento": | |
print("Saving to Memento") | |
return Memento(article) | |
def restore_from_memento(self, memento: Memento) -> str: | |
print("Restoring memento") | |
article = memento.article | |
return article | |
class Caretaker: | |
def __init__(self): | |
self.saved_articles: list[Memento] = [] | |
def add_memento(self, m: Memento) -> None: | |
self.saved_articles.append(m) | |
def get_memento(self, index: int) -> Memento: | |
return self.saved_articles[index] | |
if __name__ == "__main__": | |
care_taker = Caretaker() | |
originator = Originator() | |
saved_files = 0 | |
current_article = 0 | |
care_taker.add_memento(originator.store_in_memento("")) | |
while True: | |
save_or_undo_or_redo = input("-Save or undo or redo? S/U/R ") | |
if save_or_undo_or_redo == "S": | |
text = input("--Please enter the text to be saved: ") | |
care_taker.add_memento(originator.store_in_memento(text)) | |
current_article += 1 | |
saved_files += 1 | |
elif save_or_undo_or_redo == "U": | |
if current_article > 0: | |
current_article -= 1 | |
text = originator.restore_from_memento( | |
care_taker.get_memento(current_article) | |
) | |
print("---TEXT:", text) | |
else: | |
print("Nothing to undo") | |
elif save_or_undo_or_redo == "R": | |
if current_article < saved_files: | |
current_article += 1 | |
text = originator.restore_from_memento( | |
care_taker.get_memento(current_article) | |
) | |
print("---TEXT:", text) | |
else: | |
print("Nothing to redo") | |
else: | |
print("-Only S or U or R are accepted") |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
from abc import ABC, abstractmethod | |
class Subject(ABC): | |
@abstractmethod | |
def register(self, observer: "Observer") -> None: | |
pass | |
@abstractmethod | |
def unregister(self, observer: "Observer") -> None: | |
pass | |
@abstractmethod | |
def notify_observer(self) -> None: | |
pass | |
class Observer(ABC): | |
@abstractmethod | |
def update(self, ibm_price: float, aapl_price: float, goog_price: float) -> None: | |
pass | |
class StockGrabber(Subject): | |
def __init__(self): | |
self.observers: list[Observer] = [] | |
self.ibm_price = 0.0 | |
self.aapl_price: float = 0.0 | |
self.goog_price: float = 0.0 | |
def register(self, observer: "Observer") -> None: | |
self.observers.append(observer) | |
def unregister(self, delete_observer: "Observer") -> None: | |
self.observers.remove(delete_observer) | |
print("Observer deleted") | |
def notify_observer(self) -> None: | |
for observer in self.observers: | |
observer.update(self.ibm_price, self.aapl_price, self.goog_price) | |
def set_ibm_price(self, new_ibm_price: float) -> None: | |
self.ibm_price = new_ibm_price | |
self.notify_observer() | |
def set_aapl_price(self, new_aapl_price: float) -> None: | |
self.aapl_price = new_aapl_price | |
self.notify_observer() | |
def set_goog_price(self, new_goog_price: float) -> None: | |
self.goog_price = new_goog_price | |
self.notify_observer() | |
class StockObserver(Observer): | |
observed_id_tracker = 0 | |
def __init__(self, stock_grabber: Subject): | |
self.ibm_price = 0.0 | |
self.aapl_price: float = 0.0 | |
self.goog_price: float = 0.0 | |
StockObserver.observed_id_tracker += 1 | |
self.observer_id = StockObserver.observed_id_tracker | |
self.stock_grabber: Subject = stock_grabber | |
print("New Observer ", self.observer_id) | |
self.stock_grabber.register(self) | |
def update(self, ibm_price: float, aapl_price: float, goog_price: float) -> None: | |
self.ibm_price = ibm_price | |
self.aapl_price = aapl_price | |
self.goog_price = goog_price | |
self.print_the_prices() | |
def print_the_prices(self) -> None: | |
print( | |
f"{self.observer_id} \nIBM: {self.ibm_price} \nAAPL: {self.aapl_price} \nGOOG: {self.goog_price}\n" | |
) | |
if __name__ == "__main__": | |
stock_grabber = StockGrabber() | |
observer1 = StockObserver(stock_grabber) | |
stock_grabber.set_ibm_price(197.00) | |
stock_grabber.set_aapl_price(677.60) | |
stock_grabber.set_goog_price(676.40) | |
observer2 = StockObserver(stock_grabber) | |
stock_grabber.set_ibm_price(197.00) | |
stock_grabber.set_aapl_price(677.60) | |
stock_grabber.set_goog_price(676.40) | |
stock_grabber.unregister(observer1) | |
stock_grabber.set_ibm_price(197.00) | |
stock_grabber.set_aapl_price(677.60) | |
stock_grabber.set_goog_price(676.40) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import copy | |
from abc import ABC, abstractmethod | |
class Animal(ABC): | |
@abstractmethod | |
def __copy__(self) -> "Animal": | |
pass | |
class Sheep(Animal): | |
def __init__(self): | |
print("Sheep is made") | |
def __copy__(self) -> "Animal": | |
print("Sheep is being made") | |
return Sheep() | |
def __str__(self) -> str: | |
return "Dolly is my hero, baaaa" | |
def get_clone(animal_sample: "Animal") -> "Animal": | |
return copy.copy(animal_sample) | |
if __name__ == "__main__": | |
sally = Sheep() | |
cloned_sheep = get_clone(sally) | |
print(sally) | |
print(cloned_sheep) | |
print(f"Sally hashcode: {id(sally)}") | |
print(f"Clone hashcode: {id(cloned_sheep)}") |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
from abc import ABC, abstractmethod | |
class GetATMData(ABC): | |
@abstractmethod | |
def get_atm_data(self) -> "ATMState": | |
pass | |
@abstractmethod | |
def get_cash_in_machine(self) -> int: | |
pass | |
class ATMProxy(GetATMData): | |
def get_atm_data(self) -> "ATMState": | |
real_atm_machine = ATMMachine() | |
return real_atm_machine.get_atm_data() | |
def get_cash_in_machine(self) -> int: | |
real_atm_machine = ATMMachine() | |
return real_atm_machine.get_cash_in_machine() | |
class ATMState(ABC): | |
@abstractmethod | |
def insert_card(self) -> None: | |
pass | |
@abstractmethod | |
def eject_card(self) -> None: | |
pass | |
@abstractmethod | |
def insert_pin(self, pin_entered: int) -> None: | |
pass | |
@abstractmethod | |
def request_cash(self, cash_to_withdraw: int) -> None: | |
pass | |
# Code below copied from State Pattern | |
# ATMMachine below extends GetATMData interface | |
class ATMMachine(GetATMData): | |
def __init__(self): | |
self.has_card: ATMState = HasCard(self) | |
self.no_card: ATMState = NoCard(self) | |
self.has_correct_pin: ATMState = HasPin(self) | |
self.atm_out_of_money: ATMState = NoCash(self) | |
self.atm_state: ATMState = self.no_card | |
self.cash_in_machine: int = 2000 | |
self.correct_pin_entered: bool = False | |
if self.cash_in_machine < 0: | |
self.atm_state = self.atm_out_of_money | |
def set_atm_state(self, new_atm_state: ATMState) -> None: | |
self.atm_state = new_atm_state | |
def set_cash_in_machine(self, new_cash_in_machine: int) -> None: | |
self.cash_in_machine = new_cash_in_machine | |
def insert_card(self) -> None: | |
self.atm_state.insert_card() | |
def eject_card(self) -> None: | |
self.atm_state.eject_card() | |
def request_cash(self, cash_to_withdraw: int) -> None: | |
self.atm_state.request_cash(cash_to_withdraw) | |
def insert_pin(self, pin_entered: int) -> None: | |
self.atm_state.insert_pin(pin_entered) | |
def get_yes_card_state(self) -> ATMState: | |
return self.has_card | |
def get_no_card_state(self) -> ATMState: | |
return self.no_card | |
def get_has_pin(self) -> ATMState: | |
return self.has_correct_pin | |
def get_no_cash_state(self) -> ATMState: | |
return self.atm_out_of_money | |
def get_atm_data(self) -> "ATMState": | |
return self.atm_state | |
def get_cash_in_machine(self) -> int: | |
return self.cash_in_machine | |
class HasCard(ATMState): | |
def __init__(self, new_atm_machine: ATMMachine): | |
self.atm_machine: ATMMachine = new_atm_machine | |
def insert_card(self) -> None: | |
print("You can't enter more than one card") | |
def eject_card(self) -> None: | |
print("Card ejected") | |
self.atm_machine.set_atm_state(self.atm_machine.get_no_card_state()) | |
def insert_pin(self, pin_entered: int) -> None: | |
if pin_entered == 1234: | |
print("Correct PIN") | |
self.atm_machine.correct_pin_entered = True | |
self.atm_machine.set_atm_state(self.atm_machine.get_has_pin()) | |
else: | |
print("Wrong PIN") | |
self.atm_machine.correct_pin_entered = False | |
print("Card ejected") | |
self.atm_machine.set_atm_state(self.atm_machine.get_no_card_state()) | |
def request_cash(self, cash_to_withdraw: int) -> None: | |
print("Enter PIN first") | |
class NoCard(ATMState): | |
def __init__(self, new_atm_machine: ATMMachine): | |
self.atm_machine: ATMMachine = new_atm_machine | |
def insert_card(self) -> None: | |
print("Please enter a PIN") | |
self.atm_machine.set_atm_state(self.atm_machine.get_yes_card_state()) | |
def eject_card(self) -> None: | |
print("Enter a card first") | |
def insert_pin(self, pin_entered: int) -> None: | |
print("Enter a card first") | |
def request_cash(self, cash_to_withdraw: int) -> None: | |
print("Enter a card first") | |
class HasPin(ATMState): | |
def __init__(self, new_atm_machine: ATMMachine): | |
self.atm_machine: ATMMachine = new_atm_machine | |
def insert_card(self) -> None: | |
print("You can't enter more than one card") | |
def eject_card(self) -> None: | |
print("Card ejected") | |
self.atm_machine.set_atm_state(self.atm_machine.get_no_card_state()) | |
def insert_pin(self, pin_entered: int) -> None: | |
print("Already entered PIN") | |
def request_cash(self, cash_to_withdraw: int) -> None: | |
if cash_to_withdraw > self.atm_machine.cash_in_machine: | |
print("Don't have that cash") | |
print("Card Ejected") | |
self.atm_machine.set_atm_state(self.atm_machine.get_no_card_state()) | |
else: | |
print(f"{cash_to_withdraw} is provided by the machine") | |
self.atm_machine.set_cash_in_machine( | |
self.atm_machine.cash_in_machine - cash_to_withdraw | |
) | |
print("Card Ejected") | |
self.atm_machine.set_atm_state(self.atm_machine.get_no_card_state()) | |
if self.atm_machine.cash_in_machine <= 0: | |
self.atm_machine.set_atm_state(self.atm_machine.get_no_cash_state()) | |
class NoCash(ATMState): | |
def __init__(self, new_atm_machine: ATMMachine): | |
self.atm_machine: ATMMachine = new_atm_machine | |
def insert_card(self) -> None: | |
print("We don't have money") | |
def eject_card(self) -> None: | |
print("We don't have money. You didn't enter a card") | |
def insert_pin(self, pin_entered: int) -> None: | |
print("We don't have money") | |
def request_cash(self, cash_to_withdraw: int) -> None: | |
print("We don't have money") | |
if __name__ == "__main__": | |
atm_proxy = ATMProxy() | |
print("\nCurrent ATM State", atm_proxy.get_atm_data()) | |
print("\nCash in ATM Machine $", atm_proxy.get_cash_in_machine()) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
class _Singleton: | |
instance: "_Singleton" = None | |
def Singleton() -> _Singleton: | |
if _Singleton.instance is None: | |
_Singleton.instance = _Singleton() | |
return _Singleton.instance | |
if __name__ == "__main__": | |
singleton1 = Singleton() | |
singleton2 = Singleton() | |
assert singleton1 is singleton2, "Both are not same" |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
from abc import ABC, abstractmethod | |
class ATMState(ABC): | |
@abstractmethod | |
def insert_card(self) -> None: | |
pass | |
@abstractmethod | |
def eject_card(self) -> None: | |
pass | |
@abstractmethod | |
def insert_pin(self, pin_entered: int) -> None: | |
pass | |
@abstractmethod | |
def request_cash(self, cash_to_withdraw: int) -> None: | |
pass | |
class ATMMachine: | |
def __init__(self): | |
self.has_card: ATMState = HasCard(self) | |
self.no_card: ATMState = NoCard(self) | |
self.has_correct_pin: ATMState = HasPin(self) | |
self.atm_out_of_money: ATMState = NoCash(self) | |
self.atm_state: ATMState = self.no_card | |
self.cash_in_machine: int = 2000 | |
self.correct_pin_entered: bool = False | |
if self.cash_in_machine < 0: | |
self.atm_state = self.atm_out_of_money | |
def set_atm_state(self, new_atm_state: ATMState) -> None: | |
self.atm_state = new_atm_state | |
def set_cash_in_machine(self, new_cash_in_machine: int) -> None: | |
self.cash_in_machine = new_cash_in_machine | |
def insert_card(self) -> None: | |
self.atm_state.insert_card() | |
def eject_card(self) -> None: | |
self.atm_state.eject_card() | |
def request_cash(self, cash_to_withdraw: int) -> None: | |
self.atm_state.request_cash(cash_to_withdraw) | |
def insert_pin(self, pin_entered: int) -> None: | |
self.atm_state.insert_pin(pin_entered) | |
def get_yes_card_state(self) -> ATMState: | |
return self.has_card | |
def get_no_card_state(self) -> ATMState: | |
return self.no_card | |
def get_has_pin(self) -> ATMState: | |
return self.has_correct_pin | |
def get_no_cash_state(self) -> ATMState: | |
return self.atm_out_of_money | |
class HasCard(ATMState): | |
def __init__(self, new_atm_machine: ATMMachine): | |
self.atm_machine: ATMMachine = new_atm_machine | |
def insert_card(self) -> None: | |
print("You can't enter more than one card") | |
def eject_card(self) -> None: | |
print("Card ejected") | |
self.atm_machine.set_atm_state(self.atm_machine.get_no_card_state()) | |
def insert_pin(self, pin_entered: int) -> None: | |
if pin_entered == 1234: | |
print("Correct PIN") | |
self.atm_machine.correct_pin_entered = True | |
self.atm_machine.set_atm_state(self.atm_machine.get_has_pin()) | |
else: | |
print("Wrong PIN") | |
self.atm_machine.correct_pin_entered = False | |
print("Card ejected") | |
self.atm_machine.set_atm_state(self.atm_machine.get_no_card_state()) | |
def request_cash(self, cash_to_withdraw: int) -> None: | |
print("Enter PIN first") | |
class NoCard(ATMState): | |
def __init__(self, new_atm_machine: ATMMachine): | |
self.atm_machine: ATMMachine = new_atm_machine | |
def insert_card(self) -> None: | |
print("Please enter a PIN") | |
self.atm_machine.set_atm_state(self.atm_machine.get_yes_card_state()) | |
def eject_card(self) -> None: | |
print("Enter a card first") | |
def insert_pin(self, pin_entered: int) -> None: | |
print("Enter a card first") | |
def request_cash(self, cash_to_withdraw: int) -> None: | |
print("Enter a card first") | |
class HasPin(ATMState): | |
def __init__(self, new_atm_machine: ATMMachine): | |
self.atm_machine: ATMMachine = new_atm_machine | |
def insert_card(self) -> None: | |
print("You can't enter more than one card") | |
def eject_card(self) -> None: | |
print("Card ejected") | |
self.atm_machine.set_atm_state(self.atm_machine.get_no_card_state()) | |
def insert_pin(self, pin_entered: int) -> None: | |
print("Already entered PIN") | |
def request_cash(self, cash_to_withdraw: int) -> None: | |
if cash_to_withdraw > self.atm_machine.cash_in_machine: | |
print("Don't have that cash") | |
print("Card Ejected") | |
self.atm_machine.set_atm_state(self.atm_machine.get_no_card_state()) | |
else: | |
print(f"{cash_to_withdraw} is provided by the machine") | |
self.atm_machine.set_cash_in_machine( | |
self.atm_machine.cash_in_machine - cash_to_withdraw | |
) | |
print("Card Ejected") | |
self.atm_machine.set_atm_state(self.atm_machine.get_no_card_state()) | |
if self.atm_machine.cash_in_machine <= 0: | |
self.atm_machine.set_atm_state(self.atm_machine.get_no_cash_state()) | |
class NoCash(ATMState): | |
def __init__(self, new_atm_machine: ATMMachine): | |
self.atm_machine: ATMMachine = new_atm_machine | |
def insert_card(self) -> None: | |
print("We don't have money") | |
def eject_card(self) -> None: | |
print("We don't have money. You didn't enter a card") | |
def insert_pin(self, pin_entered: int) -> None: | |
print("We don't have money") | |
def request_cash(self, cash_to_withdraw: int) -> None: | |
print("We don't have money") | |
if __name__ == "__main__": | |
atm_machine = ATMMachine() | |
atm_machine.insert_card() | |
atm_machine.eject_card() | |
atm_machine.insert_card() | |
atm_machine.insert_pin(1234) | |
atm_machine.request_cash(2000) | |
atm_machine.insert_card() | |
atm_machine.insert_pin(1234) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
from abc import ABC, abstractmethod | |
class Animal: | |
def __init__(self): | |
self.name: str = "" | |
self.height: float = 0.0 | |
self.weight: int = 0 | |
self.fav_food: str = "" | |
self.speed: float = 0.0 | |
self.sound: str = "" | |
def fly(self) -> str: | |
return "I can't fly" | |
class Dog(Animal): | |
def __init__(self): | |
super().__init__() | |
self.sound = "Bark" | |
def dig_hole(self) -> None: | |
print("Dug a hole") | |
def fly(self) -> str: | |
return "I can't fly" | |
class Bird(Animal): | |
def __init__(self): | |
super().__init__() | |
self.sound = "Tweet" | |
def fly(self) -> str: | |
return "Flying High" | |
# ----------------- New code | |
class Flies(ABC): | |
@abstractmethod | |
def fly(self) -> str: | |
pass | |
class ItFlies(Flies): | |
def fly(self) -> str: | |
return "Flying High" | |
class CantFly(Flies): | |
def fly(self) -> str: | |
return "I can't fly" | |
class AnimalNew: | |
def __init__(self): | |
self.name: str = "" | |
self.height: float = 0.0 | |
self.weight: int = 0 | |
self.fav_food: str = "" | |
self.speed: float = 0.0 | |
self.sound: str = "" | |
self.flying_type: Flies = CantFly() | |
def fly(self) -> str: | |
return self.flying_type.fly() | |
def set_flying_ability(self, new_fly_type: Flies) -> None: | |
self.flying_type = new_fly_type | |
class DogNew(AnimalNew): | |
def __init__(self): | |
super().__init__() | |
self.sound = "Bark" | |
self.flying_type = CantFly() | |
def dig_hole(self) -> None: | |
print("Dug a hole") | |
class BirdNew(AnimalNew): | |
def __init__(self): | |
super().__init__() | |
self.sound = "Tweet" | |
self.flying_type = ItFlies() | |
if __name__ == "__main__": | |
sparky = Dog() | |
tweety = Bird() | |
print("Dog:", sparky.fly()) | |
print("Bird:", tweety.fly()) | |
sparky_new = DogNew() | |
tweety_new = BirdNew() | |
print("Dog:", sparky_new.fly()) | |
print("Bird:", tweety_new.fly()) | |
sparky_new.set_flying_ability(ItFlies()) | |
print("Dog:", sparky_new.fly()) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
from abc import ABC, abstractmethod | |
class Hoagie(ABC): | |
def make_sandwich(self) -> None: | |
self.cut_bun() | |
if self.customer_wants_meat(): | |
self.add_meat() | |
if self.customer_wants_cheese(): | |
self.add_cheese() | |
if self.customer_wants_vegetables(): | |
self.add_vegetables() | |
if self.customer_wants_condiments(): | |
self.add_condiments() | |
self.wrap_the_hoagie() | |
def cut_bun(self) -> None: | |
print("The hoagie is cut") | |
@abstractmethod | |
def add_meat(self) -> None: | |
pass | |
@abstractmethod | |
def add_cheese(self) -> None: | |
pass | |
@abstractmethod | |
def add_vegetables(self) -> None: | |
pass | |
@abstractmethod | |
def add_condiments(self) -> None: | |
pass | |
def customer_wants_meat(self) -> bool: | |
return True | |
def customer_wants_cheese(self) -> bool: | |
return True | |
def customer_wants_vegetables(self) -> bool: | |
return True | |
def customer_wants_condiments(self) -> bool: | |
return True | |
def wrap_the_hoagie(self) -> None: | |
print("Wrap the hoagie") | |
class ItalianHoagie(Hoagie): | |
def __init__(self): | |
self.meat_used: list[str] = ["Salami", "Pepperoni", "Capicola Ham"] | |
self.cheese_used: list[str] = ["Provolone"] | |
self.veggies_used: list[str] = [ | |
"Lettuce", | |
"Tomatoes", | |
"Onions", | |
"Sweet Peppers", | |
] | |
self.condiments_used: list[str] = ["Oil", "Vinegar"] | |
def add_meat(self) -> None: | |
print("Adding the meat:", end=" ") | |
for meat in self.meat_used: | |
print(meat, end=" ") | |
print() | |
def add_cheese(self) -> None: | |
print("Adding the cheese:", end=" ") | |
for cheese in self.cheese_used: | |
print(cheese, end=" ") | |
print() | |
def add_vegetables(self) -> None: | |
print("Adding the veggies:", end=" ") | |
for veggie in self.veggies_used: | |
print(veggie, end=" ") | |
print() | |
def add_condiments(self) -> None: | |
print("Adding the condiments:", end=" ") | |
for condiment in self.condiments_used: | |
print(condiment, end=" ") | |
print() | |
class VeggieHoagie(Hoagie): | |
def __init__(self): | |
self.veggies_used: list[str] = [ | |
"Lettuce", | |
"Tomatoes", | |
"Onions", | |
"Sweet Peppers", | |
] | |
self.condiments_used: list[str] = ["Oil", "Vinegar"] | |
def customer_wants_meat(self) -> bool: | |
return False | |
def customer_wants_cheese(self) -> bool: | |
return False | |
def add_meat(self) -> None: | |
pass | |
def add_cheese(self) -> None: | |
pass | |
def add_vegetables(self) -> None: | |
print("Adding the veggies:", end=" ") | |
for veggie in self.veggies_used: | |
print(veggie, end=" ") | |
print() | |
def add_condiments(self) -> None: | |
print("Adding the condiments:", end=" ") | |
for condiment in self.condiments_used: | |
print(condiment, end=" ") | |
print() | |
if __name__ == "__main__": | |
cust12_hoagie = ItalianHoagie() | |
cust12_hoagie.make_sandwich() | |
print() | |
cust13_hoagie = VeggieHoagie() | |
cust13_hoagie.make_sandwich() |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
from abc import ABC, abstractmethod | |
class Visitor(ABC): | |
@abstractmethod | |
def visit_liquor(self, liquor_item: "Liquor") -> float: | |
pass | |
@abstractmethod | |
def visit_tobacco(self, tobacco_item: "Tobacco") -> float: | |
pass | |
@abstractmethod | |
def visit_necessity(self, necessity_item: "Necessity") -> float: | |
pass | |
class TaxVisitor(Visitor): | |
def visit_liquor(self, liquor_item: "Liquor") -> float: | |
print("Liquor item: Price with Tax") | |
return liquor_item.price * 0.18 + liquor_item.price | |
def visit_tobacco(self, tobacco_item: "Tobacco") -> float: | |
print("Tobacco item: Price with Tax") | |
return tobacco_item.price * 0.32 + tobacco_item.price | |
def visit_necessity(self, necessity_item: "Necessity") -> float: | |
print("Necessity item: Price with Tax") | |
return necessity_item.price | |
class TaxHolidayVisitor(Visitor): | |
def visit_liquor(self, liquor_item: "Liquor") -> float: | |
print("Liquor item: Price with Tax") | |
return liquor_item.price * 0.10 + liquor_item.price | |
def visit_tobacco(self, tobacco_item: "Tobacco") -> float: | |
print("Tobacco item: Price with Tax") | |
return tobacco_item.price * 0.30 + tobacco_item.price | |
def visit_necessity(self, necessity_item: "Necessity") -> float: | |
print("Necessity item: Price with Tax") | |
return necessity_item.price | |
class Visitable(ABC): | |
@abstractmethod | |
def accept(self, visitor: Visitor) -> float: | |
pass | |
class Liquor(Visitable): | |
def __init__(self, item_price): | |
self.price = item_price | |
def accept(self, visitor: Visitor) -> float: | |
return visitor.visit_liquor(self) | |
class Tobacco(Visitable): | |
def __init__(self, item_price): | |
self.price = item_price | |
def accept(self, visitor: Visitor) -> float: | |
return visitor.visit_tobacco(self) | |
class Necessity(Visitable): | |
def __init__(self, item_price): | |
self.price = item_price | |
def accept(self, visitor: Visitor) -> float: | |
return visitor.visit_necessity(self) | |
if __name__ == "__main__": | |
tax_calc = TaxVisitor() | |
tax_holiday_calc = TaxHolidayVisitor() | |
milk = Necessity(3.47) | |
vodka = Liquor(11.99) | |
cigars = Tobacco(19.99) | |
print(f"{milk.accept(tax_calc)}\n") | |
print(f"{vodka.accept(tax_calc)}\n") | |
print(f"{cigars.accept(tax_calc)}\n") | |
print("TAX HOLIDAY PRICES\n") | |
print(f"{milk.accept(tax_holiday_calc)}\n") | |
print(f"{vodka.accept(tax_holiday_calc)}\n") | |
print(f"{cigars.accept(tax_holiday_calc)}\n") |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment