Skip to content

Instantly share code, notes, and snippets.

@270ajay
Created November 29, 2023 12:23
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 270ajay/a32987d30537e363d10254df76116278 to your computer and use it in GitHub Desktop.
Save 270ajay/a32987d30537e363d10254df76116278 to your computer and use it in GitHub Desktop.
Code Refactoring: Taken from Derek Banas's Refactoring Playlist on YouTube
class _FootballPlayer:
def __init__(
self,
passer_rating: int,
rushing_yard: int,
receiving_yard: int,
total_tackles: int,
interceptions: int,
avg_punt: int,
avg_kick_off_return: int,
avg_punt_return: int,
):
self.passer_rating = passer_rating
self.rushing_yard = rushing_yard
self.receiving_yard = receiving_yard
self.total_tackles = total_tackles
self.interceptions = interceptions
self.avg_punt = avg_punt
self.avg_kick_off_return = avg_kick_off_return
self.avg_punt_return = avg_punt_return
def create_quarter_back_football_player(
passer_rating: int, rushing_yards: int
) -> _FootballPlayer:
return _FootballPlayer(passer_rating, rushing_yards, 0, 0, 0, 0, 0, 0)
def create_running_back_football_player(rushing_yards: int) -> _FootballPlayer:
return _FootballPlayer(0, rushing_yards, 0, 0, 0, 0, 0, 0)
if __name__ == "__main__":
print("------- Old way ----------")
aaron_qb = _FootballPlayer(102, 100, 0, 0, 0, 0, 0, 0)
james_rb = _FootballPlayer(0, 32, 0, 0, 0, 0, 0, 0)
print("Passer rating of aaron:", aaron_qb.passer_rating)
print("Rushing yards of james:", james_rb.rushing_yard)
print("------- New way ----------")
new_aaron_qb = create_quarter_back_football_player(102, 100)
new_james_rb = create_running_back_football_player(32)
print("Passer rating of aaron:", new_aaron_qb.passer_rating)
print("Rushing yards of james:", new_james_rb.rushing_yard)
from abc import ABC, abstractmethod
class Sandwich:
def __init__(self):
self._bread: str = ""
self._vegetables: str = ""
self._meat: str = ""
self._cheese: str = ""
self._condiments: str = ""
def get_bread(self) -> str:
return self._bread
def get_vegetables(self) -> str:
return self._vegetables
def get_meat(self) -> str:
return self._meat
def get_cheese(self) -> str:
return self._cheese
def get_condiments(self) -> str:
return self._condiments
def set_bread(self, bread: str) -> None:
self._bread = bread
def set_vegetables(self, vegetables: str) -> None:
self._vegetables = vegetables
def set_meat(self, meat: str) -> None:
self._meat = meat
def set_cheese(self, cheese: str) -> None:
self._cheese = cheese
def set_condiments(self, condiments: str) -> None:
self._condiments = condiments
def __str__(self):
return (
f"{self.get_bread()} {self.get_vegetables()} {self.get_meat()} "
f"{self.get_cheese()} {self.get_condiments()} "
)
class SandwichBuilder(ABC):
def __init__(self):
self._sandwich: Sandwich = None
def get_sandwich(self) -> Sandwich:
return self._sandwich
def make_sandwich(self) -> None:
self._sandwich = Sandwich()
@abstractmethod
def build_bread(self) -> None:
pass
@abstractmethod
def build_vegetables(self) -> None:
pass
@abstractmethod
def build_meat(self) -> None:
pass
@abstractmethod
def build_cheese(self) -> None:
pass
@abstractmethod
def build_condiments(self) -> None:
pass
class BaconLettuceTomatoBuilder(SandwichBuilder):
def build_bread(self) -> None:
self._sandwich.set_bread("White bread")
def build_vegetables(self) -> None:
self._sandwich.set_vegetables("Lettuce Tomato")
def build_meat(self) -> None:
self._sandwich.set_meat("Bacon")
def build_cheese(self) -> None:
self._sandwich.set_cheese("")
def build_condiments(self) -> None:
self._sandwich.set_condiments("Mayonnaise")
class SandwichArtist:
def __init__(self):
self._sandwich_builder = None
def set_sandwich_builder(self, sandwich_builder: SandwichBuilder):
self._sandwich_builder = sandwich_builder
def get_sandwich(self) -> Sandwich:
return self._sandwich_builder.get_sandwich()
def take_sandwich_order(self) -> None:
self._sandwich_builder.make_sandwich()
self._sandwich_builder.build_bread()
self._sandwich_builder.build_vegetables()
self._sandwich_builder.build_meat()
self._sandwich_builder.build_cheese()
self._sandwich_builder.build_condiments()
if __name__ == "__main__":
paul = SandwichArtist()
paul.set_sandwich_builder(BaconLettuceTomatoBuilder())
paul.take_sandwich_order()
print(paul.get_sandwich())
class Item:
def __init__(self, item_name: str):
self._item_info: dict[str, str] = {}
self._item_name = item_name
self._children: list[Item] = []
def get_item_name(self) -> str:
return self._item_name
def set_item_name(self, item_name: str) -> None:
self._item_name = item_name
def add(self, child_node: "Item") -> None:
self._children.append(child_node)
def add_item_information(self, info_name: str, info: str) -> None:
self._item_info[info_name] = info
def get_item_information(self, info_name: str) -> str:
return self._item_info[info_name]
def __str__(self):
strings_list = [f"\n{self._item_name} "]
if self._item_info:
strings_list.append(self.display_product_info())
for child_node in self._children:
strings_list.append(str(child_node))
return "".join(strings_list)
def display_product_info(self) -> str:
product_info = ""
for info_name, info in self._item_info.items():
product_info += f"{info_name}: {info} "
return product_info
class ItemBuilder:
def __init__(self, root_name: str):
self._items: list[Item] = []
self._root: Item = Item(root_name)
self._current: Item = self._root
self._parent: Item = self._root
self.add_item(self._root)
self._root.add_item_information("Parent", self._parent.get_item_name())
def add_item_information(self, name: str, value: str) -> None:
self._current.add_item_information(name, value)
def add_child(self, child_name: str) -> None:
child_node = Item(child_name)
self.add_item(child_node)
self._current.add(child_node)
self._parent = self._current
self._current = child_node
child_node.add_item_information("Parent", self._parent.get_item_name())
def add_sibling(self, sibling_name: str) -> None:
sibling_node = Item(sibling_name)
self.add_item(sibling_node)
self._parent.add(sibling_node)
self._current = sibling_node
sibling_node.add_item_information("Parent", self._parent.get_item_name())
def add_item(self, item: Item) -> None:
self._items.append(item)
def __str__(self):
return str(self._root)
def display_all_items(self) -> None:
for item in self._items:
print(f"{item.get_item_name()}: {item.display_product_info()}")
def edit_this_item(self, item_name: str) -> None:
for item in self._items:
if item.get_item_name() == item_name:
self._current = item
self.set_item_parent(self._current.get_item_information("Parent"))
return
def set_item_parent(self, parent_item_name: str) -> None:
for item in self._items:
if item.get_item_name() == parent_item_name:
self._parent = item
return
def get_item_by_name(self, item_name_to_get: str) -> Item:
item_to_return = None
for item in self._items:
if item.get_item_name() == item_name_to_get:
item_to_return = item
break
return item_to_return
if __name__ == "__main__":
products = ItemBuilder("Products")
products.add_child("Produce")
products.add_child("Orange")
products.add_item_information("Price", "$1.00")
products.add_item_information("Stock", "100")
products.add_sibling("Apple")
products.add_sibling("Grapes")
products.edit_this_item("Products")
products.add_child("Cereal")
products.add_child("Special K")
products.add_item_information("Price", "$4.00")
products.add_sibling("Raisin Bran")
products.add_item_information("Price", "$4.00")
products.add_sibling("Fiber One")
products.add_item_information("Price", "$4.00")
products.display_all_items()
print(f"{products.get_item_by_name('Cereal')}")
from abc import ABC, abstractmethod
class Customer:
def __init__(self, age: int, is_man: bool, bill: float):
self._age = age
self._is_man = is_man
self._bill = bill
def print_final_bill(self) -> None:
percentage_off = 0.0
if self._age > 60:
percentage_off += 0.05
if not self._is_man:
percentage_off += 0.05
print(f"Bill Amount: ${self._bill - (self._bill * percentage_off)}")
# ------------------------------------
class BillPayer(ABC):
@abstractmethod
def calculate_bill(self, amount_due: float) -> None:
pass
class Command(ABC):
@abstractmethod
def execute_calculation_bill(self, amount_due: float) -> None:
pass
class WomanOver60(BillPayer):
def calculate_bill(self, amount_due: float) -> None:
print(f"Bill amount for Woman over 60: ${amount_due - (amount_due * 0.10)}")
class ManOver60(BillPayer):
def calculate_bill(self, amount_due: float) -> None:
print(f"Bill amount for Woman over 60: ${amount_due - (amount_due * 0.05)}")
class ManUnder60(BillPayer):
def calculate_bill(self, amount_due: float) -> None:
print(f"Bill amount for Woman over 60: ${amount_due}")
class Waiter(Command):
def __init__(self, the_payer: BillPayer):
self.the_payer = the_payer
def execute_calculation_bill(self, amount_due: float) -> None:
self.the_payer.calculate_bill(amount_due)
class CashRegister:
def __init__(self, the_command: Command):
self.the_command = the_command
def print_final_bill(self, amount_due: float) -> None:
self.the_command.execute_calculation_bill(amount_due)
def get_woman_over_60() -> BillPayer:
return WomanOver60()
def get_man_over_60() -> BillPayer:
return ManOver60()
def get_man_under_60() -> BillPayer:
return ManUnder60()
class CustomerGroup:
def __init__(self):
self.customers: list[BillPayer] = []
def add(self, new_payer: BillPayer) -> None:
self.customers.append(new_payer)
def get(self, customer_index: int) -> BillPayer:
return self.customers[customer_index]
if __name__ == "__main__":
# old code
bill_smith = Customer(62, True, 12)
bill_smith.print_final_bill()
print()
# new code
sally_may = get_woman_over_60()
the_waiter = Waiter(sally_may)
calculate_bill = CashRegister(the_waiter)
calculate_bill.print_final_bill(12.00)
paul_thumb = get_man_over_60()
the_waiter = Waiter(paul_thumb)
calculate_bill = CashRegister(the_waiter)
calculate_bill.print_final_bill(12.00)
customer_group = CustomerGroup()
customer_group.add(get_man_under_60())
customer_group.get(0).calculate_bill(12)
from abc import ABC, abstractmethod
class EnemyShip:
def __init__(self, current_level: int):
if current_level <= 5:
self.name: str = "Galax"
self.attack_power: int = 5
self.spaces_moved_per_turn: int = 2
elif current_level > 5 or current_level <= 10:
self.name: str = "Galaxian"
self.attack_power: int = 10
self.spaces_moved_per_turn: int = 3
elif current_level > 10:
self.name: str = "Galaxian Prime"
self.attack_power: int = 15
self.spaces_moved_per_turn: int = 4
def move_ship(self) -> None:
print(f"{self.name} moves {self.spaces_moved_per_turn} spaces")
def make_ship_attack(self) -> None:
print(f"{self.name} does {self.attack_power} damage")
class GalaxianPrime(EnemyShip):
def __init__(self, current_level: int):
super().__init__(current_level)
def move_ship(self) -> None:
print(
f"{self.name} turns on forcefield and moves {self.spaces_moved_per_turn} spaces"
)
# -------------------------------------
class Enemy(ABC):
@abstractmethod
def move_ship(self) -> None:
pass
@abstractmethod
def make_ship_attack(self) -> None:
pass
class Galax(Enemy):
def __init__(self):
self.attack_power: int = 5
self.spaces_moved_per_turn: int = 2
def move_ship(self) -> None:
print(f"Galax moves {self.spaces_moved_per_turn} spaces")
def make_ship_attack(self) -> None:
print(f"Galax does {self.attack_power} damage")
class GalaxPrime:
def __init__(self):
self.name: str = "Galaxian Prime"
self.attack_power: int = 15
self.spaces_moved_per_turn: int = 4
def turn_on_force_field(self) -> None:
print(f"{self.name} turns on force field")
def warp_to_space(self) -> None:
print(f"{self.name} warps {self.spaces_moved_per_turn} spaces")
def charge_phasers(self) -> None:
print(f"{self.name} charges phasers")
def fire_phasers(self) -> None:
print(f"{self.name} fires phasers for {self.attack_power}")
class EnemyAdapter(Enemy):
def __init__(self, galax_prime: GalaxPrime):
self.galax_prime = galax_prime
def move_ship(self) -> None:
self.galax_prime.turn_on_force_field()
self.galax_prime.warp_to_space()
def make_ship_attack(self) -> None:
self.galax_prime.charge_phasers()
self.galax_prime.fire_phasers()
if __name__ == "__main__":
level1_ship = EnemyShip(6)
level1_ship.move_ship()
level1_ship.make_ship_attack()
prime_time = GalaxianPrime(15)
prime_time.move_ship()
prime_time.make_ship_attack()
# ---------------------
print()
galax = Galax()
galax_prime = EnemyAdapter(GalaxPrime())
galax.move_ship()
galax.make_ship_attack()
galax_prime.move_ship()
galax_prime.make_ship_attack()
class ATMAccessBad:
CARD_ENTERED = "CARD ENTERED"
VALID_CARD = "VALID CARD"
VALID_PIN = "VALID_PIN"
VALID_CASH_REQUEST = "VALID_CASH_REQUEST"
DENIED = "DENIED"
CARD_NUMBER = 123456789
PIN_NUMBER = 1234
CARD_BALANCE = 1000.00
def __init__(self):
self.state: str = ATMAccessBad.CARD_ENTERED
def verify_card(self, card_number: int) -> None:
if ATMAccessBad.CARD_NUMBER == card_number:
self.state = ATMAccessBad.VALID_CARD
else:
self.state = ATMAccessBad.DENIED
def verify_pin(self, pin_number: int) -> None:
if ATMAccessBad.PIN_NUMBER == pin_number:
self.state = ATMAccessBad.VALID_PIN
else:
self.state = ATMAccessBad.DENIED
def verify_withdrawal_amount(self, withdrawal_request: float) -> None:
if ATMAccessBad.CARD_BALANCE > withdrawal_request:
self.state = ATMAccessBad.VALID_CASH_REQUEST
else:
self.state = ATMAccessBad.DENIED
# ----------------------
class ATMCardState:
def __init__(self, name: str):
self.name = name
def __str__(self):
return self.name
class ATMAccess:
CARD_ENTERED = ATMCardState("CARD ENTERED")
VALID_CARD = ATMCardState("VALID CARD")
VALID_PIN = ATMCardState("VALID_PIN")
VALID_CASH_REQUEST = ATMCardState("VALID_CASH_REQUEST")
DENIED = ATMCardState("DENIED")
CARD_NUMBER: int = 123456789
PIN_NUMBER: int = 1234
CARD_BALANCE: float = 1000.00
def __init__(self):
self.state: ATMCardState = ATMAccess.CARD_ENTERED
@property
def state(self) -> str:
return str(self._state)
@state.setter
def state(self, value: ATMCardState):
if not isinstance(value, ATMCardState):
raise TypeError(
f"state only accepts ATMCardState object. {type(value)} was assigned"
)
self._state = value
def verify_card(self, card_number: int) -> None:
if (
self.state == str(ATMAccess.CARD_ENTERED)
and ATMAccess.CARD_NUMBER == card_number
):
self.state = ATMAccess.VALID_CARD
else:
self.state = ATMAccess.DENIED
def verify_pin(self, pin_number: int) -> None:
if (
self.state == str(ATMAccess.VALID_CARD)
and ATMAccess.PIN_NUMBER == pin_number
):
self.state = ATMAccess.VALID_PIN
else:
self.state = ATMAccess.DENIED
def verify_withdrawal_amount(self, withdrawal_request: float) -> None:
if (
self.state == str(ATMAccess.VALID_PIN)
and ATMAccess.CARD_BALANCE > withdrawal_request
):
self.state = ATMAccess.VALID_CASH_REQUEST
else:
self.state = ATMAccess.DENIED
if __name__ == "__main__":
user = ATMAccessBad()
print(user.state)
user.verify_card(123456789)
print(user.state)
user.verify_pin(1234)
print(user.state)
user.verify_withdrawal_amount(99)
print(user.state)
# ---------------
print()
user_new = ATMAccess()
print(user_new.state)
user_new.verify_card(123456789)
print(user_new.state)
user_new.verify_pin(1234)
print(user_new.state)
user_new.verify_withdrawal_amount(99)
print(user_new.state)
from abc import ABC, abstractmethod
class HairCutOptions:
def __init__(self, name: str):
self.name = name
def __str__(self):
return self.name
class CalculateHairCut:
BASIC_CUT = HairCutOptions("BASIC CUT")
PERM = HairCutOptions("PERM")
HAIR_FROSTING = HairCutOptions("HAIR FROSTING")
def __init__(self, options: HairCutOptions):
if not isinstance(options, HairCutOptions):
raise TypeError(
f"Options must be of HairCutOptions. {type(options)} was assigned"
)
self.option_picked = options
def get_description(self) -> str:
if self.option_picked == CalculateHairCut.PERM:
return f"Trim the hair.\nAdd chemicals and put hair in rollers."
elif self.option_picked == CalculateHairCut.HAIR_FROSTING:
return f"Trim the hair.\nAdd chemicals and put hair in foil."
else:
return "Trim the hair."
def get_cost(self) -> float:
if self.option_picked == CalculateHairCut.PERM:
return 85.00
elif self.option_picked == CalculateHairCut.HAIR_FROSTING:
return 100.00
else:
return 10.00
# --------------------------
class HairCut(ABC):
@abstractmethod
def get_description(self) -> str:
pass
@abstractmethod
def get_cost(self) -> float:
pass
class HairCutDecorator(HairCut):
def __init__(self, hair_cut: HairCut):
self.hair_cut = hair_cut
def get_description(self) -> str:
return self.hair_cut.get_description()
def get_cost(self) -> float:
return self.hair_cut.get_cost()
class RegularHairCut(HairCut):
def get_description(self) -> str:
return "Trim the hair."
def get_cost(self) -> float:
return 10.00
class Perm(HairCutDecorator):
def __init__(self, hair_cut: HairCut):
super().__init__(hair_cut)
def get_description(self) -> str:
return (
f"{self.hair_cut.get_description()}\nAdd chemicals and put hair in rollers."
)
def get_cost(self) -> float:
return self.hair_cut.get_cost() + 75.00
if __name__ == "__main__":
perm_cut = CalculateHairCut(CalculateHairCut.PERM)
print("SERVICES")
print(perm_cut.get_description())
print(f"Price: ${perm_cut.get_cost()}")
# ---------------------
print()
perm_and_cut = Perm(RegularHairCut())
print("SERVICES")
print(perm_and_cut.get_description())
print(f"Price: ${perm_and_cut.get_cost()}")
from abc import ABC, abstractmethod
class Visitable(ABC):
@abstractmethod
def accept(self, visitor: "Visitor") -> float:
pass
class SalesTrainee(Visitable):
def __init__(self, sick_days: int, failed_tests: int, salary: float):
self.sick_days = sick_days
self.failed_tests = failed_tests
self.salary = salary
def accept(self, visitor: "Visitor") -> float:
return visitor.visit_trainee(self)
class Salesman(Visitable):
def __init__(self, total_sales_amount: float, new_customers: int):
self.total_sales_amount = total_sales_amount
self.new_customers = new_customers
def accept(self, visitor: "Visitor") -> float:
return visitor.visit_sales_man(self)
class Boss(Visitable):
def __init__(
self, total_sales_amount: float, new_customers: int, office_expense: float
):
self.total_sales_amount = total_sales_amount
self.new_customers = new_customers
self.office_expenses = office_expense
def accept(self, visitor: "Visitor") -> float:
return visitor.visit_boss(self)
class Visitor(ABC):
@abstractmethod
def visit_trainee(self, trainee: SalesTrainee) -> float:
pass
@abstractmethod
def visit_sales_man(self, sales_man: Salesman) -> float:
pass
@abstractmethod
def visit_boss(self, boss: Boss) -> float:
pass
class YearlyBonusVisitor(Visitor):
def visit_trainee(self, trainee: SalesTrainee) -> float:
print("Trainees Yearly Bonus")
yearly_bonus_percentage = (
0.10 if trainee.sick_days < 10 and trainee.failed_tests < 2 else 0.02
)
yearly_bonus_amount = trainee.salary * yearly_bonus_percentage
return yearly_bonus_amount
def visit_sales_man(self, sales_man: Salesman) -> float:
print("Salesman Yearly Bonus")
yearly_bonus_percentage = (
0.12
if sales_man.total_sales_amount > 100000 and sales_man.new_customers > 50
else 0.04
)
yearly_bonus_amount = sales_man.total_sales_amount * yearly_bonus_percentage
return yearly_bonus_amount
def visit_boss(self, boss: Boss) -> float:
print("Boss Yearly Bonus")
yearly_bonus_percentage = (
0.15 if boss.office_expenses < 50000 and boss.new_customers > 1000 else 0.04
)
yearly_bonus_amount = boss.total_sales_amount * yearly_bonus_percentage
return yearly_bonus_amount
if __name__ == "__main__":
yearly_bonus_calculator = YearlyBonusVisitor()
brad_trainee = SalesTrainee(5, 1, 20000)
tom_salesman = Salesman(150000, 62)
ross_boss = Boss(1000000, 1200, 40000)
print("YEARLY BONUS")
print(brad_trainee.accept(yearly_bonus_calculator))
print(tom_salesman.accept(yearly_bonus_calculator))
print(ross_boss.accept(yearly_bonus_calculator))
from abc import ABC, abstractmethod
class Monster(ABC):
def __init__(self, name: str):
self.name = name
self.attack_power: MonsterAttackPower = None
self.attack_range: MonsterAttackRange = None
@abstractmethod
def make_monster(self) -> None:
pass
def check_if_victim_in_range(self) -> None:
print(f"{self.name} checks if victim is {self.attack_range}")
def attack_the_victim(self) -> None:
print(f"{self.name} attacks the victim for {self.attack_power}")
def __str__(self):
info_on_monster = (
f"{self.name} attacks anything {self.attack_range} for {self.attack_power}"
)
return info_on_monster
class MonsterAttackPower(ABC):
@abstractmethod
def __str__(self):
pass
class BasicAttack(MonsterAttackPower):
def __str__(self):
return "10 in damage"
class MediumAttack(MonsterAttackPower):
def __str__(self):
return "20 in damage"
class MonsterAttackRange(ABC):
@abstractmethod
def __str__(self):
pass
class BasicRange(MonsterAttackRange):
def __str__(self):
return "5 away"
class MediumRange(MonsterAttackRange):
def __str__(self):
return "10 away"
class MonsterFactory(ABC):
@abstractmethod
def assign_attack_power(self) -> MonsterAttackPower:
pass
@abstractmethod
def assign_attack_range(self) -> MonsterAttackRange:
pass
class ZombieFactory(MonsterFactory):
def assign_attack_power(self) -> MonsterAttackPower:
return BasicAttack()
def assign_attack_range(self) -> MonsterAttackRange:
return BasicRange()
class VampireFactory(MonsterFactory):
def assign_attack_power(self) -> MonsterAttackPower:
return MediumAttack()
def assign_attack_range(self) -> MonsterAttackRange:
return MediumRange()
class Zombie(Monster):
def __init__(self, name: str, monster_factory: MonsterFactory):
super().__init__(name)
self.monster_factory = monster_factory
def make_monster(self) -> None:
print("Making a Zombie")
self.attack_power = self.monster_factory.assign_attack_power()
self.attack_range = self.monster_factory.assign_attack_range()
class Vampire(Monster):
def __init__(self, name: str, monster_factory: MonsterFactory):
super().__init__(name)
self.monster_factory = monster_factory
def make_monster(self) -> None:
print("Making a Vampire")
self.attack_power = self.monster_factory.assign_attack_power()
self.attack_range = self.monster_factory.assign_attack_range()
class MonsterBuilder(ABC):
@abstractmethod
def make_monster(self, type_of_monster: str) -> Monster:
pass
def order_a_monster(self, type_of_monster: str) -> Monster:
the_monster = self.make_monster(type_of_monster)
the_monster.make_monster()
the_monster.check_if_victim_in_range()
the_monster.attack_the_victim()
return the_monster
class OrderAMonster(MonsterBuilder):
def make_monster(self, type_of_monster: str) -> Monster:
the_monster = None
if type_of_monster == "Zombie":
monster_factory = ZombieFactory()
the_monster = Zombie("Zombie Bob", monster_factory)
elif type_of_monster == "Vampire":
monster_factory = VampireFactory()
the_monster = Vampire("Vampire Paul", monster_factory)
return the_monster
if __name__ == "__main__":
monster_builder = OrderAMonster()
zombie = monster_builder.order_a_monster("Zombie")
print(zombie, "\n")
vampire = monster_builder.order_a_monster("Vampire")
print(vampire, "\n")
class Player:
def __init__(self, name: str, scores: list[int]):
self.name: str = name
self.scores: list[int] = scores
def print_players_info(players: list[Player]) -> None:
print(f"{'Name': <15} Avg Score")
for _ in range(25):
print("`", end="")
print()
for player in players:
player_name = player.name
print(f"{player_name: <15}", end="")
total_score = 0
count_of_scores = 0
for score in player.scores:
total_score += score
count_of_scores += 1
average_score = total_score / count_of_scores
print(f"{average_score:.2f}")
def print_players_info_new(players: list[Player]) -> None:
print_title()
for player in players:
print(f"{player.name: <15}", end="")
average_score = sum(player.scores) / len(player.scores)
print(f"{average_score:.2f}")
def print_title() -> None:
print(f"{'Name':<15} Avg Score")
for _ in range(25):
print("`", end="")
print()
if __name__ == "__main__":
rob = Player("Rob", [23, 32, 43])
john = Player("John", [22, 22, 43])
harry = Player("Harry", [23, 32, 32])
# old code
print_players_info([rob, john, harry])
print("\n")
# new code
print_players_info_new([rob, john, harry])
class Product:
def __init__(
self,
quantity: int,
name: str,
price: float,
shipping_cost: float,
total_cost: float,
):
self.quantity = quantity
self.name = name
self.price = price
self.shipping_cost = shipping_cost
self.total_cost = total_cost
def get_total_cost(quantity: float, price: float) -> float:
quantity_discount = 0.0
if (quantity > 50) or ((quantity * price) > 500):
quantity_discount = 0.10
elif (quantity > 25) or ((quantity * price) > 100):
quantity_discount = 0.07
elif (quantity > 10) or ((quantity * price) > 50):
quantity_discount = 0.05
discount = ((quantity - 1) * quantity_discount) * price
return (quantity * price) - discount
def get_total_cost_new(quantity: float, price: float) -> float:
quantity_discount = 0.0
is_over_50_products = (quantity > 50) or ((quantity * price) > 500)
is_over_25_products = (quantity > 25) or ((quantity * price) > 100)
is_over_10_products = (quantity > 10) or ((quantity * price) > 50)
if is_over_50_products:
quantity_discount = 0.10
elif is_over_25_products:
quantity_discount = 0.07
elif is_over_10_products:
quantity_discount = 0.05
discount = ((quantity - 1) * quantity_discount) * price
return (quantity * price) - discount
def print_product_costs_info(products: list[Product]) -> None:
for product in products:
print(
f"Total cost for {product.quantity} {product.name} is ${product.total_cost}"
)
print(f"Cost per product {product.total_cost / product.quantity}")
print(
f"Savings per product {(product.price + product.shipping_cost) - (product.total_cost / product.quantity)}"
)
print("--------------------------")
def print_product_costs_info_new(products: list[Product]) -> None:
for product in products:
num_products = product.quantity
product_name = product.name
cost = product.total_cost
cost_with_discount = product.total_cost / product.quantity
cost_without_discount = product.price + product.shipping_cost
print(f"Total cost for {num_products} {product_name} is ${cost}")
print(f"Cost per product {cost_with_discount}")
print(f"Savings per product {cost_without_discount - cost_with_discount}")
print("--------------------------")
def print_discounted_cost(
total_cost: int, num_products: int, shipping_cost: float, discount: float
) -> None:
temp = total_cost / num_products
temp += shipping_cost
temp -= discount
print("Discounted cost: ", temp)
def print_discounted_cost_new(
total_cost: int, num_products: int, shipping_cost: float, discount: float
) -> None:
individual_product_cost = total_cost / num_products
product_cost_and_shipping = individual_product_cost + shipping_cost
discounted_product_cost = product_cost_and_shipping - discount
print("Discounted cost: ", discounted_product_cost)
if __name__ == "__main__":
print("Total cost:", get_total_cost(100, 3))
print("Total cost:", get_total_cost_new(100, 3))
print("\n")
product1 = Product(50, "Wheat", 102.0, 23.0, 125.0)
product2 = Product(20, "Barley", 102.0, 20.0, 122.0)
print_product_costs_info([product1, product2])
print("\n")
print_product_costs_info_new([product1, product2])
print("\n")
print_discounted_cost(100, 10, 10.0, 20.0)
print_discounted_cost_new(100, 10, 10.0, 20.0)
import datetime
class Customer:
def __init__(
self,
first_name: str,
last_name: str,
street: str,
city: str,
state: str,
postal_code: int,
birthday: str,
):
self.first_name = first_name
self.last_name = last_name
self.street = street
self.city = city
self.state = state
self.postal_code = postal_code
self.birthday = birthday
class Address:
def __init__(self, street: str, city: str, state: str, postal_code: int):
self.street = street
self.city = city
self.state = state
self.postal_code = postal_code
def __str__(self):
return f"{self.street} {self.city} {self.state} {self.postal_code}"
class CustomerNew:
def __init__(
self,
first_name: str,
last_name: str,
address: Address,
birthday: datetime.datetime,
):
self.first_name = first_name
self.last_name = last_name
self.address = address
self.birthday = birthday
if __name__ == "__main__":
sally_smith = Customer(
"Sally", "Smith", "123 Main St", "Perry", "Iowa", 50220, "1974-21-12"
)
sally_smith_new = CustomerNew(
"Sally",
"Smith",
Address("123 Main St", "Perry", "Iowa", 50220),
datetime.datetime(1974, 12, 21),
)
print(f"Customer name: {sally_smith_new.first_name} {sally_smith_new.last_name}")
print(f"Customer address: {sally_smith_new.address}")
print(f"Customer birthdate in isoformat: {sally_smith_new.birthday.isoformat()}")
from abc import ABC
class Customer(ABC):
PREMIER = 2
VALUED = 1
DEAD_BEAT = 3
def __init__(self):
self._customer_rating: str = ""
def get_customer_rating(self) -> str:
return self._customer_rating
def set_customer_rating(self, _customer_rating: str) -> None:
self._customer_rating = _customer_rating
class Premier(Customer):
def __init__(self):
super().__init__()
super().set_customer_rating("Premier Customer")
class Valued(Customer):
def __init__(self):
super().__init__()
super().set_customer_rating("Valued Customer")
class Deadbeat(Customer):
def __init__(self):
super().__init__()
super().set_customer_rating("Deadbeat Customer")
def get_customer(customer_type: int) -> Customer:
if customer_type == Customer.PREMIER:
return Premier()
elif customer_type == Customer.VALUED:
return Valued()
elif customer_type == Customer.DEAD_BEAT:
return Deadbeat()
else:
raise RuntimeError("Invalid customer type")
if __name__ == "__main__":
# Old code
premier_customer = Premier()
print(premier_customer.get_customer_rating())
# New code
premier_customer_new = get_customer(Customer.PREMIER)
print(premier_customer_new.get_customer_rating())
def print_bag_fees(bag_weights: list[int]) -> None:
num_bags = len(bag_weights)
bag_fees = 0
for i in range(num_bags):
if i <= 1:
if bag_weights[i] < 50:
if i == 0:
bag_fees += 25
else:
bag_fees += 35
elif bag_weights[i] < 70:
bag_fees += 100
elif (i > 1) and (bag_weights[i] < 70):
bag_fees += 150
else:
bag_fees += 200
print("Bag fees:", bag_fees)
def print_bag_fees_new(bag_weights: list[int]) -> None:
bag_fees = 0
for bag_number in range(len(bag_weights)):
if bag_weights[bag_number] < 50:
bag_fees += _fee_for_bag_under_50_lbs(bag_number)
elif bag_weights[bag_number] < 70:
bag_fees += _fee_for_bag_50_to_70_lbs(bag_number)
else:
bag_fees += 200
print("Bag fees:", bag_fees)
def _fee_for_bag_under_50_lbs(bag_number: int) -> int:
return 25 if bag_number < 1 else 35
def _fee_for_bag_50_to_70_lbs(bag_number: int) -> int:
return 100 if bag_number < 2 else 150
# --------------------------------------
# Replacing conditional with polymorphism
# --------------------------------------
class Animal:
def __init__(self, sound: str):
self._sound = sound
def get_sound(self) -> str:
return self._sound
def set_sound(self, sound) -> None:
self._sound = sound
class Dog(Animal):
def __init__(self, sound):
super().__init__(sound)
class Cat(Animal):
def __init__(self, sound):
super().__init__(sound)
def make_sound(animal_name: str) -> None:
if animal_name == "Dog":
print("Woof")
elif animal_name == "Cat":
print("Meow")
else:
raise RuntimeError("Unknown animal")
def make_sound_new(animal: Animal) -> None:
print(animal.get_sound())
if __name__ == "__main__":
print_bag_fees([25, 55, 75])
print_bag_fees_new([25, 55, 75])
rex = Dog("Woof")
sophie = Cat("Meow")
make_sound(type(rex).__name__)
make_sound(type(sophie).__name__)
make_sound_new(rex)
make_sound_new(sophie)
from abc import ABC, abstractmethod
class Employees:
"""Problem with this approach: when we had to add new feature like bonus
amount, we had to change so many parts of this class."""
def __init__(
self, bonus: bool = False, salary: float = 0.0, bonus_amount: float = 0.15
):
self._has_bonus = bonus
self._salary = salary
self._bonus_amount = bonus_amount
def get_salary(self) -> float:
if self._has_bonus:
return self._salary + (self._salary * self._bonus_amount)
return self._salary
def set_salary(self, salary: float) -> None:
self._salary = salary
# -------------------------------------------
class Pay(ABC):
@abstractmethod
def get_pay(self, salary: float) -> float:
pass
class GetsBonus(Pay):
def get_pay(self, salary: float) -> float:
return salary + (salary * 0.15)
class NoBonus(Pay):
def get_pay(self, salary: float) -> float:
return salary
class Bonus20Percent(Pay):
def get_pay(self, salary: float) -> float:
return salary + (salary * 0.20)
class EmployeesNew:
def __init__(self, salary: float = 0.0, pay_type: Pay = NoBonus()):
self._salary = salary
self._pay_type = pay_type
def set_bonus_option(self, pay_type: Pay) -> None:
self._pay_type = pay_type
def get_pay(self) -> float:
return self._pay_type.get_pay(self._salary)
if __name__ == "__main__":
sales_man = Employees(True, 15000.0, 0.20)
secretary = Employees(False, 20000.0)
print(sales_man.get_salary())
print(secretary.get_salary())
sales_man_new = EmployeesNew(15000.0)
secretary_new = EmployeesNew(25000.0)
print("Salesman:", sales_man_new.get_pay())
print("Secretary:", secretary_new.get_pay())
sales_man_new.set_bonus_option(GetsBonus())
secretary_new.set_bonus_option(Bonus20Percent())
print("Salesman:", sales_man_new.get_pay())
print("Secretary:", secretary_new.get_pay())
from abc import ABC, abstractmethod
class Hamburger:
def __init__(self, wants_condiments: bool):
self.wants_condiments = wants_condiments
def make_sandwich(self) -> None:
print("\n---------- NEW ORDER ----------\n")
self.cut_bun()
self.add_meat()
self.add_vegetables()
if self.wants_condiments:
self.add_condiments()
self.wrap_sandwich()
def cut_bun(self) -> None:
print("The bun was cut")
def add_meat(self) -> None:
print("Hamburger added")
def add_vegetables(self) -> None:
print("Lettuce, onions, and tomatoes")
def wrap_sandwich(self) -> None:
print("The sandwich was wrapped")
def add_condiments(self) -> None:
print("Special sauce added")
class VeggieSub:
def __init__(self, wants_condiments: bool):
self.wants_condiments = wants_condiments
def make_sandwich(self) -> None:
print("\n---------- NEW ORDER ----------\n")
self.cut_bun()
self.add_vegetables()
if self.wants_condiments:
self.add_condiments()
self.wrap_sandwich()
def cut_bun(self) -> None:
print("The bun was cut")
def add_vegetables(self) -> None:
print("Lettuce, onions, and tomatoes")
def wrap_sandwich(self) -> None:
print("The sandwich was wrapped")
def add_condiments(self) -> None:
print("Vinegar and oil added")
# -------------------------------------------------
class Sandwich(ABC):
def make_sandwich(self) -> None:
print("\n---------- NEW ORDER ----------\n")
self.cut_bun()
if self.wants_meat():
self.add_meat()
self.add_vegetables()
if self.wants_condiments():
self.add_condiments()
self.wrap_sandwich()
@abstractmethod
def add_meat(self) -> None:
pass
@abstractmethod
def add_condiments(self) -> None:
pass
def cut_bun(self) -> None:
print("The bun was cut")
def add_vegetables(self) -> None:
print("Lettuce, onions, and tomatoes")
def wrap_sandwich(self) -> None:
print("The sandwich was wrapped")
def wants_meat(self) -> bool:
return True
def wants_condiments(self) -> bool:
return True
class HamburgerNew(Sandwich):
def add_meat(self) -> None:
print("Hamburger added")
def add_condiments(self) -> None:
print("Special sauce added")
class VeggieSubNew(Sandwich):
def wants_meat(self) -> bool:
return False
def add_meat(self) -> None:
pass
def add_condiments(self) -> None:
print("Vinegar and oil added")
if __name__ == "__main__":
customer1 = Hamburger(True)
customer1.make_sandwich()
customer2 = VeggieSub(True)
customer2.make_sandwich()
# new code
customer1_new = HamburgerNew()
customer1_new.make_sandwich()
customer2_new = VeggieSubNew()
customer2_new.make_sandwich()
from abc import ABC, abstractmethod
class ProductComponent(ABC):
def add(self, new_product_component: "ProductComponent") -> None:
pass
def remove(self, new_product_component: "ProductComponent") -> None:
pass
def get_product_component(self, component_index: int) -> "ProductComponent":
return None
def get_product_group_name(self) -> str:
return None
@abstractmethod
def display_product_info(self) -> None:
pass
class ProductGroup(ProductComponent):
def __init__(self, product_group_name: str):
self._product_components: list[ProductComponent] = []
self._product_group_name = product_group_name
def add(self, new_product_component: ProductComponent) -> None:
self._product_components.append(new_product_component)
def remove(self, new_product_component: ProductComponent) -> None:
self._product_components.remove(new_product_component)
def get_product_component(self, component_index: int) -> "ProductComponent":
return self._product_components[component_index]
def get_product_group_name(self) -> str:
return self._product_group_name
def display_product_info(self):
print(self.get_product_group_name())
for product_component in self._product_components:
product_component.display_product_info()
print()
class Product(ProductComponent):
def __init__(self, product_name: str, product_price: float):
self._product_name = product_name
self._product_price = product_price
def get_product_name(self) -> str:
return self._product_name
def get_product_price(self) -> float:
return self._product_price
def set_product_name(self, product_name: str) -> None:
self._product_name = product_name
def set_product_price(self, product_price: float) -> None:
self._product_price = product_price
def display_product_info(self) -> None:
print(f"{self.get_product_name()} ${self.get_product_price()}")
if __name__ == "__main__":
every_product = ProductGroup("All Products\n")
produce = ProductGroup("Produce")
cereal = ProductGroup("Cereal")
every_product.add(produce)
every_product.add(cereal)
produce.add(Product("Tomato", 1.99))
produce.add(Product("Orange", 0.99))
produce.add(Product("Potato", 0.35))
cereal.add(Product("Special K", 3.68))
cereal.add(Product("Cheerios", 3.68))
cereal.add(Product("Raisin Bran", 3.68))
every_product.display_product_info()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment