From ba0f98d5a6e8a408110cf25e68e4eec65a0b27b2 Mon Sep 17 00:00:00 2001 From: iamsuryansh Date: Sat, 21 Jun 2025 17:54:20 +0530 Subject: [PATCH] Added Python code for first 12 lectures. Identical implementation from Java Code --- Lecture 02/Python Code/Abstraction.py | 84 ++++++++++++ Lecture 02/Python Code/Encapsulation.py | 74 +++++++++++ Lecture 03/Python Code/DynamicPolymorphism.py | 105 +++++++++++++++ Lecture 03/Python Code/Inheritance.py | 82 ++++++++++++ .../StaticAndDynamicPolymorphism.py | 112 ++++++++++++++++ Lecture 03/Python Code/StaticPolymorphism.py | 49 +++++++ Lecture 05/Python Code/LSP/LSPFollowed.py | 70 ++++++++++ .../Python Code/LSP/LSPFollowedWrongly.py | 35 +++++ Lecture 05/Python Code/LSP/LSPViolated.py | 68 ++++++++++ Lecture 05/Python Code/OCP/OCPFollowed.py | 58 +++++++++ .../Python Code/OCP/OCPFollowedWrongly.py | 36 ++++++ Lecture 05/Python Code/OCP/OCPViolated.py | 32 +++++ Lecture 05/Python Code/SRP/SRPFollowed.py | 42 ++++++ .../Python Code/SRP/SRPFollowedWrongly.py | 35 +++++ Lecture 05/Python Code/SRP/SRPViolated.py | 31 +++++ Lecture 06/Python Code/DIP/DIPFollowed.py | 32 +++++ Lecture 06/Python Code/DIP/DIPViolated.py | 23 ++++ Lecture 06/Python Code/ISP/ISPFollowed.py | 50 +++++++ Lecture 06/Python Code/ISP/ISPViolated.py | 56 ++++++++ .../LSP-Rules/MethodRules/PostConditions.py | 32 +++++ .../LSP-Rules/MethodRules/PreConditions.py | 20 +++ .../PropertiesRules/ClassInvariants.py | 25 ++++ .../PropertiesRules/HistoryConstraint.py | 27 ++++ .../SignatureRules/MethodArgumentRule.py | 24 ++++ .../Bad Design/DocumentEditorClient.py | 50 +++++++ .../Good Design/DocumentEditorClient.py | 122 ++++++++++++++++++ .../Python Code/StrategyDesignPattern.py | 91 +++++++++++++ Lecture 09/Python Code/AbstractFactory.py | 122 ++++++++++++++++++ Lecture 09/Python Code/FactoryMethod.py | 71 ++++++++++ Lecture 09/Python Code/SimpleFactory.py | 44 +++++++ Lecture 10/Python Code/NoSingleton.py | 9 ++ Lecture 10/Python Code/SimpleSingleton.py | 18 +++ .../Python Code/ThreadSafeEagerSingleton.py | 31 +++++ Lecture 11/Python Code/Tomato/Main.py | 24 ++++ Lecture 11/Python Code/Tomato/TomatoApp.py | 85 ++++++++++++ .../__pycache__/TomatoApp.cpython-313.pyc | Bin 0 -> 6078 bytes .../Tomato/factories/NowOrderFactory.py | 7 + .../Tomato/factories/OrderFactory.py | 6 + .../Tomato/factories/ScheduledOrderFactory.py | 7 + .../NowOrderFactory.cpython-313.pyc | Bin 0 -> 850 bytes .../__pycache__/OrderFactory.cpython-313.pyc | Bin 0 -> 665 bytes .../ScheduledOrderFactory.cpython-313.pyc | Bin 0 -> 896 bytes .../Tomato/managers/OrderManager.py | 12 ++ .../Tomato/managers/RestaurantManager.py | 18 +++ .../RestaurantManager.cpython-313.pyc | Bin 0 -> 1599 bytes Lecture 11/Python Code/Tomato/models/Cart.py | 19 +++ .../Tomato/models/DeliveryOrder.py | 12 ++ .../Python Code/Tomato/models/MenuItem.py | 23 ++++ Lecture 11/Python Code/Tomato/models/Order.py | 32 +++++ .../Python Code/Tomato/models/PickupOrder.py | 12 ++ .../Python Code/Tomato/models/Restaurant.py | 27 ++++ Lecture 11/Python Code/Tomato/models/User.py | 14 ++ .../models/__pycache__/Cart.cpython-313.pyc | Bin 0 -> 1678 bytes .../__pycache__/MenuItem.cpython-313.pyc | Bin 0 -> 1482 bytes .../models/__pycache__/Order.cpython-313.pyc | Bin 0 -> 2222 bytes .../__pycache__/Restaurant.cpython-313.pyc | Bin 0 -> 1810 bytes .../models/__pycache__/User.cpython-313.pyc | Bin 0 -> 1007 bytes .../Tomato/services/NotificationService.py | 15 +++ .../NotificationService.cpython-313.pyc | Bin 0 -> 1799 bytes .../strategies/CreditCardPaymentStrategy.py | 5 + .../Tomato/strategies/PaymentStrategy.py | 6 + .../Tomato/strategies/UPIPaymentStrategy.py | 5 + .../Python Code/Tomato/utils/TimeUtils.py | 6 + .../Python Code/ObserverDesignPattern.py | 83 ++++++++++++ 64 files changed, 2178 insertions(+) create mode 100644 Lecture 02/Python Code/Abstraction.py create mode 100644 Lecture 02/Python Code/Encapsulation.py create mode 100644 Lecture 03/Python Code/DynamicPolymorphism.py create mode 100644 Lecture 03/Python Code/Inheritance.py create mode 100644 Lecture 03/Python Code/StaticAndDynamicPolymorphism.py create mode 100644 Lecture 03/Python Code/StaticPolymorphism.py create mode 100644 Lecture 05/Python Code/LSP/LSPFollowed.py create mode 100644 Lecture 05/Python Code/LSP/LSPFollowedWrongly.py create mode 100644 Lecture 05/Python Code/LSP/LSPViolated.py create mode 100644 Lecture 05/Python Code/OCP/OCPFollowed.py create mode 100644 Lecture 05/Python Code/OCP/OCPFollowedWrongly.py create mode 100644 Lecture 05/Python Code/OCP/OCPViolated.py create mode 100644 Lecture 05/Python Code/SRP/SRPFollowed.py create mode 100644 Lecture 05/Python Code/SRP/SRPFollowedWrongly.py create mode 100644 Lecture 05/Python Code/SRP/SRPViolated.py create mode 100644 Lecture 06/Python Code/DIP/DIPFollowed.py create mode 100644 Lecture 06/Python Code/DIP/DIPViolated.py create mode 100644 Lecture 06/Python Code/ISP/ISPFollowed.py create mode 100644 Lecture 06/Python Code/ISP/ISPViolated.py create mode 100644 Lecture 06/Python Code/LSP-Rules/MethodRules/PostConditions.py create mode 100644 Lecture 06/Python Code/LSP-Rules/MethodRules/PreConditions.py create mode 100644 Lecture 06/Python Code/LSP-Rules/PropertiesRules/ClassInvariants.py create mode 100644 Lecture 06/Python Code/LSP-Rules/PropertiesRules/HistoryConstraint.py create mode 100644 Lecture 06/Python Code/LSP-Rules/SignatureRules/MethodArgumentRule.py create mode 100644 Lecture 07/Python Code/Bad Design/DocumentEditorClient.py create mode 100644 Lecture 07/Python Code/Good Design/DocumentEditorClient.py create mode 100644 Lecture 08/Python Code/StrategyDesignPattern.py create mode 100644 Lecture 09/Python Code/AbstractFactory.py create mode 100644 Lecture 09/Python Code/FactoryMethod.py create mode 100644 Lecture 09/Python Code/SimpleFactory.py create mode 100644 Lecture 10/Python Code/NoSingleton.py create mode 100644 Lecture 10/Python Code/SimpleSingleton.py create mode 100644 Lecture 10/Python Code/ThreadSafeEagerSingleton.py create mode 100644 Lecture 11/Python Code/Tomato/Main.py create mode 100644 Lecture 11/Python Code/Tomato/TomatoApp.py create mode 100644 Lecture 11/Python Code/Tomato/__pycache__/TomatoApp.cpython-313.pyc create mode 100644 Lecture 11/Python Code/Tomato/factories/NowOrderFactory.py create mode 100644 Lecture 11/Python Code/Tomato/factories/OrderFactory.py create mode 100644 Lecture 11/Python Code/Tomato/factories/ScheduledOrderFactory.py create mode 100644 Lecture 11/Python Code/Tomato/factories/__pycache__/NowOrderFactory.cpython-313.pyc create mode 100644 Lecture 11/Python Code/Tomato/factories/__pycache__/OrderFactory.cpython-313.pyc create mode 100644 Lecture 11/Python Code/Tomato/factories/__pycache__/ScheduledOrderFactory.cpython-313.pyc create mode 100644 Lecture 11/Python Code/Tomato/managers/OrderManager.py create mode 100644 Lecture 11/Python Code/Tomato/managers/RestaurantManager.py create mode 100644 Lecture 11/Python Code/Tomato/managers/__pycache__/RestaurantManager.cpython-313.pyc create mode 100644 Lecture 11/Python Code/Tomato/models/Cart.py create mode 100644 Lecture 11/Python Code/Tomato/models/DeliveryOrder.py create mode 100644 Lecture 11/Python Code/Tomato/models/MenuItem.py create mode 100644 Lecture 11/Python Code/Tomato/models/Order.py create mode 100644 Lecture 11/Python Code/Tomato/models/PickupOrder.py create mode 100644 Lecture 11/Python Code/Tomato/models/Restaurant.py create mode 100644 Lecture 11/Python Code/Tomato/models/User.py create mode 100644 Lecture 11/Python Code/Tomato/models/__pycache__/Cart.cpython-313.pyc create mode 100644 Lecture 11/Python Code/Tomato/models/__pycache__/MenuItem.cpython-313.pyc create mode 100644 Lecture 11/Python Code/Tomato/models/__pycache__/Order.cpython-313.pyc create mode 100644 Lecture 11/Python Code/Tomato/models/__pycache__/Restaurant.cpython-313.pyc create mode 100644 Lecture 11/Python Code/Tomato/models/__pycache__/User.cpython-313.pyc create mode 100644 Lecture 11/Python Code/Tomato/services/NotificationService.py create mode 100644 Lecture 11/Python Code/Tomato/services/__pycache__/NotificationService.cpython-313.pyc create mode 100644 Lecture 11/Python Code/Tomato/strategies/CreditCardPaymentStrategy.py create mode 100644 Lecture 11/Python Code/Tomato/strategies/PaymentStrategy.py create mode 100644 Lecture 11/Python Code/Tomato/strategies/UPIPaymentStrategy.py create mode 100644 Lecture 11/Python Code/Tomato/utils/TimeUtils.py create mode 100644 Lecture 12/Python Code/ObserverDesignPattern.py diff --git a/Lecture 02/Python Code/Abstraction.py b/Lecture 02/Python Code/Abstraction.py new file mode 100644 index 0000000..e1b76e6 --- /dev/null +++ b/Lecture 02/Python Code/Abstraction.py @@ -0,0 +1,84 @@ +from abc import ABC, abstractmethod + +class Car(ABC): + """ + Car Interface --> Acts as an interface for the outside world to operate the car. + This interface tells 'WHAT' all it can do rather than 'HOW' it does that. + """ + + @abstractmethod + def start_engine(self): + pass + + @abstractmethod + def shift_gear(self, gear): + pass + + @abstractmethod + def accelerate(self): + pass + + @abstractmethod + def brake(self): + pass + + @abstractmethod + def stop_engine(self): + pass + + +class SportsCar(Car): + """ + Concrete class that provides implementation details of the Car interface. + Represents a real-world sports car with all functionalities. + """ + + def __init__(self, brand, model): + self.brand = brand + self.model = model + self.is_engine_on = False + self.current_speed = 0 + self.current_gear = 0 + + def start_engine(self): + self.is_engine_on = True + print(f"{self.brand} {self.model} : Engine starts with a roar!") + + def shift_gear(self, gear): + if not self.is_engine_on: + print(f"{self.brand} {self.model} : Engine is off! Cannot shift gear.") + return + self.current_gear = gear + print(f"{self.brand} {self.model} : Shifted to gear {self.current_gear}") + + def accelerate(self): + if not self.is_engine_on: + print(f"{self.brand} {self.model} : Engine is off! Cannot accelerate.") + return + self.current_speed += 20 + print(f"{self.brand} {self.model} : Accelerating to {self.current_speed} km/h") + + def brake(self): + self.current_speed -= 20 + if self.current_speed < 0: + self.current_speed = 0 + print(f"{self.brand} {self.model} : Braking! Speed is now {self.current_speed} km/h") + + def stop_engine(self): + self.is_engine_on = False + self.current_gear = 0 + self.current_speed = 0 + print(f"{self.brand} {self.model} : Engine turned off.") + + +# Main Method +if __name__ == "__main__": + my_car = SportsCar("Ford", "Mustang") + + my_car.start_engine() + my_car.shift_gear(1) + my_car.accelerate() + my_car.shift_gear(2) + my_car.accelerate() + my_car.brake() + my_car.stop_engine() \ No newline at end of file diff --git a/Lecture 02/Python Code/Encapsulation.py b/Lecture 02/Python Code/Encapsulation.py new file mode 100644 index 0000000..131c769 --- /dev/null +++ b/Lecture 02/Python Code/Encapsulation.py @@ -0,0 +1,74 @@ +class SportsCar: + """ + SportsCar class demonstrates encapsulation by combining characteristics (attributes) + and behaviors (methods) into a single class and restricting access to certain attributes + using private variables and getter/setter methods. + """ + + def __init__(self, brand, model): + self.__brand = brand + self.__model = model + self.__is_engine_on = False + self.__current_speed = 0 + self.__current_gear = 0 + self.__tyre_company = None # Introduced to explain setters + + # Getter for current speed + def get_speed(self): + return self.__current_speed + + # Getter for tyre company + def get_tyre_company(self): + return self.__tyre_company + + # Setter for tyre company + def set_tyre_company(self, tyre_company): + self.__tyre_company = tyre_company + + # Method to start the engine + def start_engine(self): + self.__is_engine_on = True + print(f"{self.__brand} {self.__model} : Engine starts with a roar!") + + # Method to shift gear + def shift_gear(self, gear): + self.__current_gear = gear + print(f"{self.__brand} {self.__model} : Shifted to gear {self.__current_gear}") + + # Method to accelerate + def accelerate(self): + if not self.__is_engine_on: + print(f"{self.__brand} {self.__model} : Engine is off! Cannot accelerate.") + return + self.__current_speed += 20 + print(f"{self.__brand} {self.__model} : Accelerating to {self.__current_speed} km/h") + + # Method to brake + def brake(self): + self.__current_speed -= 20 + if self.__current_speed < 0: + self.__current_speed = 0 + print(f"{self.__brand} {self.__model} : Braking! Speed is now {self.__current_speed} km/h") + + # Method to stop the engine + def stop_engine(self): + self.__is_engine_on = False + self.__current_gear = 0 + self.__current_speed = 0 + print(f"{self.__brand} {self.__model} : Engine turned off.") + + +# Main Method +if __name__ == "__main__": + my_sports_car = SportsCar("Ford", "Mustang") + + my_sports_car.start_engine() + my_sports_car.shift_gear(1) + my_sports_car.accelerate() + my_sports_car.shift_gear(2) + my_sports_car.accelerate() + my_sports_car.brake() + my_sports_car.stop_engine() + + # Accessing speed using getter + print(f"Current Speed of My Sports Car is {my_sports_car.get_speed()}") \ No newline at end of file diff --git a/Lecture 03/Python Code/DynamicPolymorphism.py b/Lecture 03/Python Code/DynamicPolymorphism.py new file mode 100644 index 0000000..e8446a9 --- /dev/null +++ b/Lecture 03/Python Code/DynamicPolymorphism.py @@ -0,0 +1,105 @@ +from abc import ABC, abstractmethod + +class Car(ABC): + """ + Abstract base class representing a generic car. + """ + + def __init__(self, brand, model): + self.brand = brand + self.model = model + self.is_engine_on = False + self.current_speed = 0 + + def start_engine(self): + self.is_engine_on = True + print(f"{self.brand} {self.model} : Engine started.") + + def stop_engine(self): + self.is_engine_on = False + self.current_speed = 0 + print(f"{self.brand} {self.model} : Engine turned off.") + + @abstractmethod + def accelerate(self): + pass + + @abstractmethod + def brake(self): + pass + + +class ManualCar(Car): + """ + Represents a manual car with gear shifting functionality. + """ + + def __init__(self, brand, model): + super().__init__(brand, model) + self.current_gear = 0 + + def shift_gear(self, gear): + self.current_gear = gear + print(f"{self.brand} {self.model} : Shifted to gear {self.current_gear}") + + def accelerate(self): + if not self.is_engine_on: + print(f"{self.brand} {self.model} : Cannot accelerate! Engine is off.") + return + self.current_speed += 20 + print(f"{self.brand} {self.model} : Accelerating to {self.current_speed} km/h") + + def brake(self): + self.current_speed -= 20 + if self.current_speed < 0: + self.current_speed = 0 + print(f"{self.brand} {self.model} : Braking! Speed is now {self.current_speed} km/h") + + +class ElectricCar(Car): + """ + Represents an electric car with battery functionality. + """ + + def __init__(self, brand, model): + super().__init__(brand, model) + self.battery_level = 100 + + def charge_battery(self): + self.battery_level = 100 + print(f"{self.brand} {self.model} : Battery fully charged!") + + def accelerate(self): + if not self.is_engine_on: + print(f"{self.brand} {self.model} : Cannot accelerate! Engine is off.") + return + if self.battery_level <= 0: + print(f"{self.brand} {self.model} : Battery dead! Cannot accelerate.") + return + self.battery_level -= 10 + self.current_speed += 15 + print(f"{self.brand} {self.model} : Accelerating to {self.current_speed} km/h. Battery at {self.battery_level}%.") + + def brake(self): + self.current_speed -= 15 + if self.current_speed < 0: + self.current_speed = 0 + print(f"{self.brand} {self.model} : Regenerative braking! Speed is now {self.current_speed} km/h. Battery at {self.battery_level}%.") + + +if __name__ == "__main__": + my_manual_car = ManualCar("Suzuki", "WagonR") + my_manual_car.start_engine() + my_manual_car.accelerate() + my_manual_car.accelerate() + my_manual_car.brake() + my_manual_car.stop_engine() + + print("----------------------") + + my_electric_car = ElectricCar("Tesla", "Model S") + my_electric_car.start_engine() + my_electric_car.accelerate() + my_electric_car.accelerate() + my_electric_car.brake() + my_electric_car.stop_engine() \ No newline at end of file diff --git a/Lecture 03/Python Code/Inheritance.py b/Lecture 03/Python Code/Inheritance.py new file mode 100644 index 0000000..461bcd2 --- /dev/null +++ b/Lecture 03/Python Code/Inheritance.py @@ -0,0 +1,82 @@ +class Car: + """ + Represents a generic car with common attributes and methods. + """ + + def __init__(self, brand, model): + self.brand = brand + self.model = model + self.is_engine_on = False + self.current_speed = 0 + + # Common methods for all cars + def start_engine(self): + self.is_engine_on = True + print(f"{self.brand} {self.model} : Engine started.") + + def stop_engine(self): + self.is_engine_on = False + self.current_speed = 0 + print(f"{self.brand} {self.model} : Engine turned off.") + + def accelerate(self): + if not self.is_engine_on: + print(f"{self.brand} {self.model} : Cannot accelerate! Engine is off.") + return + self.current_speed += 20 + print(f"{self.brand} {self.model} : Accelerating to {self.current_speed} km/h") + + def brake(self): + self.current_speed -= 20 + if self.current_speed < 0: + self.current_speed = 0 + print(f"{self.brand} {self.model} : Braking! Speed is now {self.current_speed} km/h") + + +class ManualCar(Car): + """ + Represents a manual car with gear-shifting functionality. + """ + + def __init__(self, brand, model): + super().__init__(brand, model) + self.current_gear = 0 + + # Specialized method for Manual Car + def shift_gear(self, gear): + self.current_gear = gear + print(f"{self.brand} {self.model} : Shifted to gear {self.current_gear}") + + +class ElectricCar(Car): + """ + Represents an electric car with battery functionality. + """ + + def __init__(self, brand, model): + super().__init__(brand, model) + self.battery_level = 100 + + # Specialized method for Electric Car + def charge_battery(self): + self.battery_level = 100 + print(f"{self.brand} {self.model} : Battery fully charged!") + + +# Main Method +if __name__ == "__main__": + my_manual_car = ManualCar("Suzuki", "WagonR") + my_manual_car.start_engine() + my_manual_car.shift_gear(1) # Specific to Manual Car + my_manual_car.accelerate() + my_manual_car.brake() + my_manual_car.stop_engine() + + print("----------------------") + + my_electric_car = ElectricCar("Tesla", "Model S") + my_electric_car.charge_battery() # Specific to Electric Car + my_electric_car.start_engine() + my_electric_car.accelerate() + my_electric_car.brake() + my_electric_car.stop_engine() \ No newline at end of file diff --git a/Lecture 03/Python Code/StaticAndDynamicPolymorphism.py b/Lecture 03/Python Code/StaticAndDynamicPolymorphism.py new file mode 100644 index 0000000..6539d25 --- /dev/null +++ b/Lecture 03/Python Code/StaticAndDynamicPolymorphism.py @@ -0,0 +1,112 @@ +from abc import ABC, abstractmethod + +class Car(ABC): + """ + Abstract base class representing a generic car. + """ + + def __init__(self, brand, model): + self.brand = brand + self.model = model + self.is_engine_on = False + self.current_speed = 0 + + def start_engine(self): + self.is_engine_on = True + print(f"{self.brand} {self.model} : Engine started.") + + def stop_engine(self): + self.is_engine_on = False + self.current_speed = 0 + print(f"{self.brand} {self.model} : Engine turned off.") + + @abstractmethod + def accelerate(self, speed=None): + pass + + @abstractmethod + def brake(self): + pass + + +class ManualCar(Car): + """ + Represents a manual car with gear shifting functionality. + """ + + def __init__(self, brand, model): + super().__init__(brand, model) + self.current_gear = 0 + + def shift_gear(self, gear): + self.current_gear = gear + print(f"{self.brand} {self.model} : Shifted to gear {self.current_gear}") + + def accelerate(self, speed=None): + if not self.is_engine_on: + print(f"{self.brand} {self.model} : Cannot accelerate! Engine is off.") + return + if speed is None: + self.current_speed += 20 + else: + self.current_speed += speed + print(f"{self.brand} {self.model} : Accelerating to {self.current_speed} km/h") + + def brake(self): + self.current_speed -= 20 + if self.current_speed < 0: + self.current_speed = 0 + print(f"{self.brand} {self.model} : Braking! Speed is now {self.current_speed} km/h") + + +class ElectricCar(Car): + """ + Represents an electric car with battery functionality. + """ + + def __init__(self, brand, model): + super().__init__(brand, model) + self.battery_level = 100 + + def charge_battery(self): + self.battery_level = 100 + print(f"{self.brand} {self.model} : Battery fully charged!") + + def accelerate(self, speed=None): + if not self.is_engine_on: + print(f"{self.brand} {self.model} : Cannot accelerate! Engine is off.") + return + if self.battery_level <= 0: + print(f"{self.brand} {self.model} : Battery dead! Cannot accelerate.") + return + if speed is None: + self.battery_level -= 10 + self.current_speed += 15 + else: + self.battery_level -= 10 + speed + self.current_speed += speed + print(f"{self.brand} {self.model} : Accelerating to {self.current_speed} km/h. Battery at {self.battery_level}%.") + + def brake(self): + self.current_speed -= 15 + if self.current_speed < 0: + self.current_speed = 0 + print(f"{self.brand} {self.model} : Regenerative braking! Speed is now {self.current_speed} km/h. Battery at {self.battery_level}%.") + + +if __name__ == "__main__": + my_manual_car = ManualCar("Ford", "Mustang") + my_manual_car.start_engine() + my_manual_car.accelerate() + my_manual_car.accelerate(30) + my_manual_car.brake() + my_manual_car.stop_engine() + + print("----------------------") + + my_electric_car = ElectricCar("Tesla", "Model S") + my_electric_car.start_engine() + my_electric_car.accelerate() + my_electric_car.accelerate(25) + my_electric_car.brake() + my_electric_car.stop_engine() \ No newline at end of file diff --git a/Lecture 03/Python Code/StaticPolymorphism.py b/Lecture 03/Python Code/StaticPolymorphism.py new file mode 100644 index 0000000..eb7efac --- /dev/null +++ b/Lecture 03/Python Code/StaticPolymorphism.py @@ -0,0 +1,49 @@ +class ManualCar: + """ + Represents a manual car demonstrating static polymorphism (method overloading). + """ + + def __init__(self, brand, model): + self.brand = brand + self.model = model + self.is_engine_on = False + self.current_speed = 0 + self.current_gear = 0 + + def start_engine(self): + self.is_engine_on = True + print(f"{self.brand} {self.model} : Engine started.") + + def stop_engine(self): + self.is_engine_on = False + self.current_speed = 0 + print(f"{self.brand} {self.model} : Engine turned off.") + + def accelerate(self, speed=None): + if not self.is_engine_on: + print(f"{self.brand} {self.model} : Cannot accelerate! Engine is off.") + return + if speed is None: + self.current_speed += 20 + else: + self.current_speed += speed + print(f"{self.brand} {self.model} : Accelerating to {self.current_speed} km/h") + + def brake(self): + self.current_speed -= 20 + if self.current_speed < 0: + self.current_speed = 0 + print(f"{self.brand} {self.model} : Braking! Speed is now {self.current_speed} km/h") + + def shift_gear(self, gear): + self.current_gear = gear + print(f"{self.brand} {self.model} : Shifted to gear {self.current_gear}") + + +if __name__ == "__main__": + my_manual_car = ManualCar("Suzuki", "WagonR") + my_manual_car.start_engine() + my_manual_car.accelerate() + my_manual_car.accelerate(40) + my_manual_car.brake() + my_manual_car.stop_engine() \ No newline at end of file diff --git a/Lecture 05/Python Code/LSP/LSPFollowed.py b/Lecture 05/Python Code/LSP/LSPFollowed.py new file mode 100644 index 0000000..931f77c --- /dev/null +++ b/Lecture 05/Python Code/LSP/LSPFollowed.py @@ -0,0 +1,70 @@ +from abc import ABC, abstractmethod + +# DepositOnlyAccount interface +class DepositOnlyAccount(ABC): + @abstractmethod + def deposit(self, amount): + pass + +# WithdrawableAccount interface +class WithdrawableAccount(DepositOnlyAccount): + @abstractmethod + def withdraw(self, amount): + pass + +class SavingAccount(WithdrawableAccount): + def __init__(self): + self.balance = 0 + + def deposit(self, amount): + self.balance += amount + print(f"Deposited: {amount} in Savings Account. New Balance: {self.balance}") + + def withdraw(self, amount): + if self.balance >= amount: + self.balance -= amount + print(f"Withdrawn: {amount} from Savings Account. New Balance: {self.balance}") + else: + print("Insufficient funds in Savings Account!") + +class CurrentAccount(WithdrawableAccount): + def __init__(self): + self.balance = 0 + + def deposit(self, amount): + self.balance += amount + print(f"Deposited: {amount} in Current Account. New Balance: {self.balance}") + + def withdraw(self, amount): + if self.balance >= amount: + self.balance -= amount + print(f"Withdrawn: {amount} from Current Account. New Balance: {self.balance}") + else: + print("Insufficient funds in Current Account!") + +class FixedTermAccount(DepositOnlyAccount): + def __init__(self): + self.balance = 0 + + def deposit(self, amount): + self.balance += amount + print(f"Deposited: {amount} in Fixed Term Account. New Balance: {self.balance}") + +class BankClient: + def __init__(self, withdrawable_accounts, deposit_only_accounts): + self.withdrawable_accounts = withdrawable_accounts + self.deposit_only_accounts = deposit_only_accounts + + def process_transactions(self): + for acc in self.withdrawable_accounts: + acc.deposit(1000) + acc.withdraw(500) + for acc in self.deposit_only_accounts: + acc.deposit(5000) + +if __name__ == "__main__": + withdrawable_accounts = [SavingAccount(), CurrentAccount()] + deposit_only_accounts = [FixedTermAccount()] + + client = BankClient(withdrawable_accounts, deposit_only_accounts) + client.process_transactions() \ No newline at end of file diff --git a/Lecture 05/Python Code/LSP/LSPFollowedWrongly.py b/Lecture 05/Python Code/LSP/LSPFollowedWrongly.py new file mode 100644 index 0000000..6544b38 --- /dev/null +++ b/Lecture 05/Python Code/LSP/LSPFollowedWrongly.py @@ -0,0 +1,35 @@ +class Account: + """ + Represents a generic account with deposit and withdraw functionality. + """ + + def __init__(self): + self.balance = 0 + + def deposit(self, amount): + self.balance += amount + print(f"Deposited: {amount}. New Balance: {self.balance}") + + def withdraw(self, amount): + if self.balance >= amount: + self.balance -= amount + print(f"Withdrawn: {amount}. New Balance: {self.balance}") + else: + print("Insufficient funds!") + +class FixedTermAccount(Account): + """ + Represents a fixed-term account where withdrawal is not allowed. + """ + + def withdraw(self, amount): + print("Withdrawal not allowed in Fixed Term Account!") + +if __name__ == "__main__": + saving_account = Account() + saving_account.deposit(1000) + saving_account.withdraw(500) + + fixed_term_account = FixedTermAccount() + fixed_term_account.deposit(2000) + fixed_term_account.withdraw(500) # Violates LSP as withdrawal is not allowed \ No newline at end of file diff --git a/Lecture 05/Python Code/LSP/LSPViolated.py b/Lecture 05/Python Code/LSP/LSPViolated.py new file mode 100644 index 0000000..c284055 --- /dev/null +++ b/Lecture 05/Python Code/LSP/LSPViolated.py @@ -0,0 +1,68 @@ +from abc import ABC, abstractmethod + +class Account(ABC): + @abstractmethod + def deposit(self, amount): + pass + + @abstractmethod + def withdraw(self, amount): + pass + +class SavingAccount(Account): + def __init__(self): + self.balance = 0 + + def deposit(self, amount): + self.balance += amount + print(f"Deposited: {amount} in Savings Account. New Balance: {self.balance}") + + def withdraw(self, amount): + if self.balance >= amount: + self.balance -= amount + print(f"Withdrawn: {amount} from Savings Account. New Balance: {self.balance}") + else: + print("Insufficient funds in Savings Account!") + +class CurrentAccount(Account): + def __init__(self): + self.balance = 0 + + def deposit(self, amount): + self.balance += amount + print(f"Deposited: {amount} in Current Account. New Balance: {self.balance}") + + def withdraw(self, amount): + if self.balance >= amount: + self.balance -= amount + print(f"Withdrawn: {amount} from Current Account. New Balance: {self.balance}") + else: + print("Insufficient funds in Current Account!") + +class FixedTermAccount(Account): + def __init__(self): + self.balance = 0 + + def deposit(self, amount): + self.balance += amount + print(f"Deposited: {amount} in Fixed Term Account. New Balance: {self.balance}") + + def withdraw(self, amount): + raise NotImplementedError("Withdrawal not allowed in Fixed Term Account!") + +class BankClient: + def __init__(self, accounts): + self.accounts = accounts + + def process_transactions(self): + for acc in self.accounts: + acc.deposit(1000) + try: + acc.withdraw(500) + except NotImplementedError as e: + print(f"Exception: {e}") + +if __name__ == "__main__": + accounts = [SavingAccount(), CurrentAccount(), FixedTermAccount()] + client = BankClient(accounts) + client.process_transactions() \ No newline at end of file diff --git a/Lecture 05/Python Code/OCP/OCPFollowed.py b/Lecture 05/Python Code/OCP/OCPFollowed.py new file mode 100644 index 0000000..623ed4d --- /dev/null +++ b/Lecture 05/Python Code/OCP/OCPFollowed.py @@ -0,0 +1,58 @@ +from abc import ABC, abstractmethod +class Product: + def __init__(self, name, price): + self.name = name + self.price = price + +class ShoppingCart: + def __init__(self): + self.products = [] + + def add_product(self, product): + self.products.append(product) + + def calculate_total(self): + return sum(p.price for p in self.products) + +class ShoppingCartPrinter: + def __init__(self, cart): + self.cart = cart + + def print_invoice(self): + print("Shopping Cart Invoice:") + for product in self.cart.products: + print(f"{product.name} - Rs {product.price}") + print(f"Total: Rs {self.cart.calculate_total()}") + +class Persistence(ABC): + @abstractmethod + def save(self, cart): + pass + +class SQLPersistence(Persistence): + def save(self, cart): + print("Saving shopping cart to SQL DB...") + +class MongoPersistence(Persistence): + def save(self, cart): + print("Saving shopping cart to MongoDB...") + +class FilePersistence(Persistence): + def save(self, cart): + print("Saving shopping cart to a file...") + +if __name__ == "__main__": + cart = ShoppingCart() + cart.add_product(Product("Laptop", 50000)) + cart.add_product(Product("Mouse", 2000)) + + printer = ShoppingCartPrinter(cart) + printer.print_invoice() + + sql_persistence = SQLPersistence() + mongo_persistence = MongoPersistence() + file_persistence = FilePersistence() + + sql_persistence.save(cart) + mongo_persistence.save(cart) + file_persistence.save(cart) \ No newline at end of file diff --git a/Lecture 05/Python Code/OCP/OCPFollowedWrongly.py b/Lecture 05/Python Code/OCP/OCPFollowedWrongly.py new file mode 100644 index 0000000..53abd74 --- /dev/null +++ b/Lecture 05/Python Code/OCP/OCPFollowedWrongly.py @@ -0,0 +1,36 @@ +class Product: + def __init__(self, name, price): + self.name = name + self.price = price + +class ShoppingCart: + """ + Represents a shopping cart that violates OCP by hardcoding persistence methods. + """ + + def __init__(self): + self.products = [] + + def add_product(self, product): + self.products.append(product) + + def calculate_total(self): + return sum(p.price for p in self.products) + + def save_to_sql_database(self): + print("Saving shopping cart to SQL DB...") + + def save_to_mongo_database(self): + print("Saving shopping cart to MongoDB...") + + def save_to_file(self): + print("Saving shopping cart to a file...") + +if __name__ == "__main__": + cart = ShoppingCart() + cart.add_product(Product("Laptop", 50000)) + cart.add_product(Product("Mouse", 2000)) + + cart.save_to_sql_database() + cart.save_to_mongo_database() + cart.save_to_file() \ No newline at end of file diff --git a/Lecture 05/Python Code/OCP/OCPViolated.py b/Lecture 05/Python Code/OCP/OCPViolated.py new file mode 100644 index 0000000..8b9c71d --- /dev/null +++ b/Lecture 05/Python Code/OCP/OCPViolated.py @@ -0,0 +1,32 @@ +class Product: + def __init__(self, name, price): + self.name = name + self.price = price + +class ShoppingCart: + def __init__(self): + self.products = [] + + def add_product(self, product): + self.products.append(product) + + def calculate_total(self): + return sum(p.price for p in self.products) + + def save_to_sql_database(self): + print("Saving shopping cart to SQL DB...") + + def save_to_mongo_database(self): + print("Saving shopping cart to MongoDB...") + + def save_to_file(self): + print("Saving shopping cart to a file...") + +if __name__ == "__main__": + cart = ShoppingCart() + cart.add_product(Product("Laptop", 50000)) + cart.add_product(Product("Mouse", 2000)) + + cart.save_to_sql_database() + cart.save_to_mongo_database() + cart.save_to_file() \ No newline at end of file diff --git a/Lecture 05/Python Code/SRP/SRPFollowed.py b/Lecture 05/Python Code/SRP/SRPFollowed.py new file mode 100644 index 0000000..6c8290c --- /dev/null +++ b/Lecture 05/Python Code/SRP/SRPFollowed.py @@ -0,0 +1,42 @@ +class Product: + def __init__(self, name, price): + self.name = name + self.price = price + +class ShoppingCart: + def __init__(self): + self.products = [] + + def add_product(self, product): + self.products.append(product) + + def calculate_total(self): + return sum(p.price for p in self.products) + +class ShoppingCartPrinter: + def __init__(self, cart): + self.cart = cart + + def print_invoice(self): + print("Shopping Cart Invoice:") + for product in self.cart.products: + print(f"{product.name} - Rs {product.price}") + print(f"Total: Rs {self.cart.calculate_total()}") + +class ShoppingCartStorage: + def __init__(self, cart): + self.cart = cart + + def save_to_database(self): + print("Saving shopping cart to database...") + +if __name__ == "__main__": + cart = ShoppingCart() + cart.add_product(Product("Laptop", 50000)) + cart.add_product(Product("Mouse", 2000)) + + printer = ShoppingCartPrinter(cart) + printer.print_invoice() + + storage = ShoppingCartStorage(cart) + storage.save_to_database() \ No newline at end of file diff --git a/Lecture 05/Python Code/SRP/SRPFollowedWrongly.py b/Lecture 05/Python Code/SRP/SRPFollowedWrongly.py new file mode 100644 index 0000000..9a9c6de --- /dev/null +++ b/Lecture 05/Python Code/SRP/SRPFollowedWrongly.py @@ -0,0 +1,35 @@ +class Product: + def __init__(self, name, price): + self.name = name + self.price = price + +class ShoppingCart: + """ + Represents a shopping cart that violates SRP by handling multiple responsibilities. + """ + + def __init__(self): + self.products = [] + + def add_product(self, product): + self.products.append(product) + + def calculate_total(self): + return sum(p.price for p in self.products) + + def print_invoice(self): + print("Shopping Cart Invoice:") + for product in self.products: + print(f"{product.name} - Rs {product.price}") + print(f"Total: Rs {self.calculate_total()}") + + def save_to_database(self): + print("Saving shopping cart to database...") + +if __name__ == "__main__": + cart = ShoppingCart() + cart.add_product(Product("Laptop", 50000)) + cart.add_product(Product("Mouse", 2000)) + + cart.print_invoice() + cart.save_to_database() \ No newline at end of file diff --git a/Lecture 05/Python Code/SRP/SRPViolated.py b/Lecture 05/Python Code/SRP/SRPViolated.py new file mode 100644 index 0000000..0d7c232 --- /dev/null +++ b/Lecture 05/Python Code/SRP/SRPViolated.py @@ -0,0 +1,31 @@ +class Product: + def __init__(self, name, price): + self.name = name + self.price = price + +class ShoppingCart: + def __init__(self): + self.products = [] + + def add_product(self, product): + self.products.append(product) + + def calculate_total(self): + return sum(p.price for p in self.products) + + def print_invoice(self): + print("Shopping Cart Invoice:") + for product in self.products: + print(f"{product.name} - Rs {product.price}") + print(f"Total: Rs {self.calculate_total()}") + + def save_to_database(self): + print("Saving shopping cart to database...") + +if __name__ == "__main__": + cart = ShoppingCart() + cart.add_product(Product("Laptop", 50000)) + cart.add_product(Product("Mouse", 2000)) + + cart.print_invoice() + cart.save_to_database() \ No newline at end of file diff --git a/Lecture 06/Python Code/DIP/DIPFollowed.py b/Lecture 06/Python Code/DIP/DIPFollowed.py new file mode 100644 index 0000000..bfae589 --- /dev/null +++ b/Lecture 06/Python Code/DIP/DIPFollowed.py @@ -0,0 +1,32 @@ +# Abstraction (Interface) +class Database: + def save(self, data): + pass + +# MySQL implementation (Low-level module) +class MySQLDatabase(Database): + def save(self, data): + print(f"Executing SQL Query: INSERT INTO users VALUES('{data}');") + +# MongoDB implementation (Low-level module) +class MongoDBDatabase(Database): + def save(self, data): + print(f"Executing MongoDB Function: db.users.insert({{name: '{data}'}})") + +# High-level module (Now loosely coupled via Dependency Injection) +class UserService: + def __init__(self, database: Database): + self.db = database + + def store_user(self, user): + self.db.save(user) + +if __name__ == "__main__": + mysql = MySQLDatabase() + mongodb = MongoDBDatabase() + + service1 = UserService(mysql) + service1.store_user("Aditya") + + service2 = UserService(mongodb) + service2.store_user("Rohit") \ No newline at end of file diff --git a/Lecture 06/Python Code/DIP/DIPViolated.py b/Lecture 06/Python Code/DIP/DIPViolated.py new file mode 100644 index 0000000..61849d0 --- /dev/null +++ b/Lecture 06/Python Code/DIP/DIPViolated.py @@ -0,0 +1,23 @@ +class MySQLDatabase: # Low-level module + def save_to_sql(self, data): + print(f"Executing SQL Query: INSERT INTO users VALUES('{data}');") + +class MongoDBDatabase: # Low-level module + def save_to_mongo(self, data): + print(f"Executing MongoDB Function: db.users.insert({{name: '{data}'}})") + +class UserService: # High-level module (Tightly coupled) + def __init__(self): + self.sql_db = MySQLDatabase() + self.mongo_db = MongoDBDatabase() + + def store_user_to_sql(self, user): + self.sql_db.save_to_sql(user) + + def store_user_to_mongo(self, user): + self.mongo_db.save_to_mongo(user) + +if __name__ == "__main__": + service = UserService() + service.store_user_to_sql("Aditya") + service.store_user_to_mongo("Rohit") \ No newline at end of file diff --git a/Lecture 06/Python Code/ISP/ISPFollowed.py b/Lecture 06/Python Code/ISP/ISPFollowed.py new file mode 100644 index 0000000..aae6e89 --- /dev/null +++ b/Lecture 06/Python Code/ISP/ISPFollowed.py @@ -0,0 +1,50 @@ +# Separate interface for 2D shapes +class TwoDimensionalShape: + def area(self): + pass + +# Separate interface for 3D shapes +class ThreeDimensionalShape: + def area(self): + pass + + def volume(self): + pass + +# Square implements only the 2D interface +class Square(TwoDimensionalShape): + def __init__(self, side): + self.side = side + + def area(self): + return self.side * self.side + +# Rectangle implements only the 2D interface +class Rectangle(TwoDimensionalShape): + def __init__(self, length, width): + self.length = length + self.width = width + + def area(self): + return self.length * self.width + +# Cube implements the 3D interface +class Cube(ThreeDimensionalShape): + def __init__(self, side): + self.side = side + + def area(self): + return 6 * self.side * self.side + + def volume(self): + return self.side * self.side * self.side + +if __name__ == "__main__": + square = Square(5) + rectangle = Rectangle(4, 6) + cube = Cube(3) + + print("Square Area:", square.area()) + print("Rectangle Area:", rectangle.area()) + print("Cube Area:", cube.area()) + print("Cube Volume:", cube.volume()) \ No newline at end of file diff --git a/Lecture 06/Python Code/ISP/ISPViolated.py b/Lecture 06/Python Code/ISP/ISPViolated.py new file mode 100644 index 0000000..798e7ec --- /dev/null +++ b/Lecture 06/Python Code/ISP/ISPViolated.py @@ -0,0 +1,56 @@ +# Single interface for all shapes (Violates ISP) +class Shape: + def area(self): + pass + + def volume(self): + pass # 2D shapes don't have volume! + +# Square is a 2D shape but is forced to implement volume() +class Square(Shape): + def __init__(self, side): + self.side = side + + def area(self): + return self.side * self.side + + def volume(self): + raise NotImplementedError("Volume not applicable for Square") + +# Rectangle is also a 2D shape but is forced to implement volume() +class Rectangle(Shape): + def __init__(self, length, width): + self.length = length + self.width = width + + def area(self): + return self.length * self.width + + def volume(self): + raise NotImplementedError("Volume not applicable for Rectangle") + +# Cube is a 3D shape, so it actually has a volume +class Cube(Shape): + def __init__(self, side): + self.side = side + + def area(self): + return 6 * self.side * self.side + + def volume(self): + return self.side * self.side * self.side + +if __name__ == "__main__": + square = Square(5) + rectangle = Rectangle(4, 6) + cube = Cube(3) + + print("Square Area:", square.area()) + print("Rectangle Area:", rectangle.area()) + print("Cube Area:", cube.area()) + print("Cube Volume:", cube.volume()) + + try: + print("Square Volume:", square.volume()) # Will raise an exception + except NotImplementedError as e: + print("Exception:", e) \ No newline at end of file diff --git a/Lecture 06/Python Code/LSP-Rules/MethodRules/PostConditions.py b/Lecture 06/Python Code/LSP-Rules/MethodRules/PostConditions.py new file mode 100644 index 0000000..9ce8e09 --- /dev/null +++ b/Lecture 06/Python Code/LSP-Rules/MethodRules/PostConditions.py @@ -0,0 +1,32 @@ +# A Postcondition must be satisfied after a method is executed. +# Subclasses can strengthen the Postcondition but cannot weaken it. + +class Car: + def __init__(self): + self.speed = 0 + + def accelerate(self): + print("Accelerating") + self.speed += 20 + + # PostCondition: Speed must reduce after brake + def brake(self): + print("Applying brakes") + self.speed -= 20 + +# Subclass can strengthen postcondition - Does not violate LSP +class HybridCar(Car): + def __init__(self): + super().__init__() + self.charge = 0 + + # PostCondition: Speed must reduce after brake + # PostCondition: Charge must increase. + def brake(self): + print("Applying brakes") + self.speed -= 20 + self.charge += 10 + +if __name__ == "__main__": + hybrid_car = HybridCar() + hybrid_car.brake() # Works fine: HybridCar reduces speed and also increases charge \ No newline at end of file diff --git a/Lecture 06/Python Code/LSP-Rules/MethodRules/PreConditions.py b/Lecture 06/Python Code/LSP-Rules/MethodRules/PreConditions.py new file mode 100644 index 0000000..010d07c --- /dev/null +++ b/Lecture 06/Python Code/LSP-Rules/MethodRules/PreConditions.py @@ -0,0 +1,20 @@ +# A Precondition must be satisfied before a method can be executed. +# Subclasses can weaken the precondition but cannot strengthen it. + +class User: + # Precondition: Password must be at least 8 characters long + def set_password(self, password): + if len(password) < 8: + raise ValueError("Password must be at least 8 characters long!") + print("Password set successfully") + +class AdminUser(User): + # Precondition: Password must be at least 6 characters + def set_password(self, password): + if len(password) < 6: + raise ValueError("Password must be at least 6 characters long!") + print("Password set successfully") + +if __name__ == "__main__": + user = AdminUser() + user.set_password("Admin1") # Works fine: AdminUser allows shorter passwords \ No newline at end of file diff --git a/Lecture 06/Python Code/LSP-Rules/PropertiesRules/ClassInvariants.py b/Lecture 06/Python Code/LSP-Rules/PropertiesRules/ClassInvariants.py new file mode 100644 index 0000000..cd4019f --- /dev/null +++ b/Lecture 06/Python Code/LSP-Rules/PropertiesRules/ClassInvariants.py @@ -0,0 +1,25 @@ +# Invariant: Balance cannot be negative +class BankAccount: + def __init__(self, balance): + if balance < 0: + raise ValueError("Balance can't be negative") + self.balance = balance + + def withdraw(self, amount): + if self.balance - amount < 0: + raise RuntimeError("Insufficient funds") + self.balance -= amount + print(f"Amount withdrawn. Remaining balance is {self.balance}") + +# Breaks invariant: Should not be allowed. +class CheatAccount(BankAccount): + def withdraw(self, amount): + self.balance -= amount # LSP break! Negative balance allowed + print(f"Amount withdrawn. Remaining balance is {self.balance}") + +if __name__ == "__main__": + account = BankAccount(100) + account.withdraw(50) + + cheat_account = CheatAccount(100) + cheat_account.withdraw(150) # Violates invariant \ No newline at end of file diff --git a/Lecture 06/Python Code/LSP-Rules/PropertiesRules/HistoryConstraint.py b/Lecture 06/Python Code/LSP-Rules/PropertiesRules/HistoryConstraint.py new file mode 100644 index 0000000..198227a --- /dev/null +++ b/Lecture 06/Python Code/LSP-Rules/PropertiesRules/HistoryConstraint.py @@ -0,0 +1,27 @@ +# Subclass methods should not allow state changes that the base class never allowed. + +class BankAccount: + def __init__(self, balance): + if balance < 0: + raise ValueError("Balance can't be negative") + self.balance = balance + + def withdraw(self, amount): + if self.balance - amount < 0: + raise RuntimeError("Insufficient funds") + self.balance -= amount + print(f"Amount withdrawn. Remaining balance is {self.balance}") + +class FixedDepositAccount(BankAccount): + def withdraw(self, amount): + raise RuntimeError("Withdraw not allowed in Fixed Deposit") # LSP break! + +if __name__ == "__main__": + account = BankAccount(100) + account.withdraw(50) + + fixed_account = FixedDepositAccount(100) + try: + fixed_account.withdraw(50) # Violates history constraint + except RuntimeError as e: + print(f"Exception: {e}") \ No newline at end of file diff --git a/Lecture 06/Python Code/LSP-Rules/SignatureRules/MethodArgumentRule.py b/Lecture 06/Python Code/LSP-Rules/SignatureRules/MethodArgumentRule.py new file mode 100644 index 0000000..38d01f3 --- /dev/null +++ b/Lecture 06/Python Code/LSP-Rules/SignatureRules/MethodArgumentRule.py @@ -0,0 +1,24 @@ +# Method Argument Rule: +# Subtype method arguments can be identical or wider than the supertype. + +class Parent: + def print(self, msg): + print(f"Parent: {msg}") + +class Child(Parent): + def print(self, msg): + print(f"Child: {msg}") + +class Client: + def __init__(self, parent): + self.parent = parent + + def print_msg(self): + self.parent.print("Hello") + +if __name__ == "__main__": + parent = Parent() + child = Child() + + client = Client(child) + client.print_msg() \ No newline at end of file diff --git a/Lecture 07/Python Code/Bad Design/DocumentEditorClient.py b/Lecture 07/Python Code/Bad Design/DocumentEditorClient.py new file mode 100644 index 0000000..b3fbd01 --- /dev/null +++ b/Lecture 07/Python Code/Bad Design/DocumentEditorClient.py @@ -0,0 +1,50 @@ +import os + +class DocumentEditor: + def __init__(self): + self.document_elements = [] + self.rendered_document = "" + + # Adds text as a plain string + def add_text(self, text): + self.document_elements.append(text) + + # Adds an image represented by its file path + def add_image(self, image_path): + self.document_elements.append(image_path) + + # Renders the document by checking the type of each element at runtime + def render_document(self): + if not self.rendered_document: + result = [] + for element in self.document_elements: + if len(element) > 4 and (element.endswith(".jpg") or element.endswith(".png")): + result.append(f"[Image: {element}]") + else: + result.append(element) + self.rendered_document = "\n".join(result) + return self.rendered_document + + # Saves the rendered document to a file + def save_to_file(self): + try: + with open("document.txt", "w") as writer: + writer.write(self.render_document()) + print("Document saved to document.txt") + except IOError: + print("Error: Unable to open file for writing.") + +class DocumentEditorClient: + @staticmethod + def main(): + editor = DocumentEditor() + editor.add_text("Hello, world!") + editor.add_image("picture.jpg") + editor.add_text("This is a document editor.") + + print(editor.render_document()) + + editor.save_to_file() + +if __name__ == "__main__": + DocumentEditorClient.main() \ No newline at end of file diff --git a/Lecture 07/Python Code/Good Design/DocumentEditorClient.py b/Lecture 07/Python Code/Good Design/DocumentEditorClient.py new file mode 100644 index 0000000..a86335b --- /dev/null +++ b/Lecture 07/Python Code/Good Design/DocumentEditorClient.py @@ -0,0 +1,122 @@ +from abc import ABC, abstractmethod + +# Interface for document elements +class DocumentElement(ABC): + @abstractmethod + def render(self): + pass + +# Concrete implementation for text elements +class TextElement(DocumentElement): + def __init__(self, text): + self.text = text + + def render(self): + return self.text + +# Concrete implementation for image elements +class ImageElement(DocumentElement): + def __init__(self, image_path): + self.image_path = image_path + + def render(self): + return f"[Image: {self.image_path}]" + +# NewLineElement represents a line break in the document. +class NewLineElement(DocumentElement): + def render(self): + return "\n" + +# TabSpaceElement represents a tab space in the document. +class TabSpaceElement(DocumentElement): + def render(self): + return "\t" + +# Document class responsible for holding a collection of elements +class Document: + def __init__(self): + self.document_elements = [] + + def add_element(self, element): + self.document_elements.append(element) + + # Renders the document by concatenating the render output of all elements. + def render(self): + return "".join([element.render() for element in self.document_elements]) + +# Persistence Interface +class Persistence(ABC): + @abstractmethod + def save(self, data): + pass + +# FileStorage implementation of Persistence +class FileStorage(Persistence): + def save(self, data): + try: + with open("document.txt", "w") as out_file: + out_file.write(data) + print("Document saved to document.txt") + except IOError: + print("Error: Unable to open file for writing.") + +# Placeholder DBStorage implementation +class DBStorage(Persistence): + def save(self, data): + # Save to DB (placeholder) + print("Data saved to database (placeholder).") + +# DocumentEditor class managing client interactions +class DocumentEditor: + def __init__(self, document, storage): + self.document = document + self.storage = storage + self.rendered_document = "" + + def add_text(self, text): + self.document.add_element(TextElement(text)) + + def add_image(self, image_path): + self.document.add_element(ImageElement(image_path)) + + # Adds a new line to the document. + def add_new_line(self): + self.document.add_element(NewLineElement()) + + # Adds a tab space to the document. + def add_tab_space(self): + self.document.add_element(TabSpaceElement()) + + def render_document(self): + if not self.rendered_document: + self.rendered_document = self.document.render() + return self.rendered_document + + def save_document(self): + self.storage.save(self.render_document()) + +class DocumentEditorClient: + @staticmethod + def main(): + document = Document() + persistence = FileStorage() + + editor = DocumentEditor(document, persistence) + + # Simulate a client using the editor with common text formatting features. + editor.add_text("Hello, world!") + editor.add_new_line() + editor.add_text("This is a real-world document editor example.") + editor.add_new_line() + editor.add_tab_space() + editor.add_text("Indented text after a tab space.") + editor.add_new_line() + editor.add_image("picture.jpg") + + # Render and display the final document. + print(editor.render_document()) + + editor.save_document() + +if __name__ == "__main__": + DocumentEditorClient.main() \ No newline at end of file diff --git a/Lecture 08/Python Code/StrategyDesignPattern.py b/Lecture 08/Python Code/StrategyDesignPattern.py new file mode 100644 index 0000000..b1bc83b --- /dev/null +++ b/Lecture 08/Python Code/StrategyDesignPattern.py @@ -0,0 +1,91 @@ +from abc import ABC, abstractmethod + +# --- Strategy Interface for Walk --- +class WalkableRobot(ABC): + @abstractmethod + def walk(self): + pass + +# --- Concrete Strategies for Walk --- +class NormalWalk(WalkableRobot): + def walk(self): + print("Walking normally...") + +class NoWalk(WalkableRobot): + def walk(self): + print("Cannot walk.") + +# --- Strategy Interface for Talk --- +class TalkableRobot(ABC): + @abstractmethod + def talk(self): + pass + +# --- Concrete Strategies for Talk --- +class NormalTalk(TalkableRobot): + def talk(self): + print("Talking normally...") + +class NoTalk(TalkableRobot): + def talk(self): + print("Cannot talk.") + +# --- Strategy Interface for Fly --- +class FlyableRobot(ABC): + @abstractmethod + def fly(self): + pass + +# --- Concrete Strategies for Fly --- +class NormalFly(FlyableRobot): + def fly(self): + print("Flying normally...") + +class NoFly(FlyableRobot): + def fly(self): + print("Cannot fly.") + +# --- Robot Base Class --- +class Robot(ABC): + def __init__(self, walk_behavior: WalkableRobot, talk_behavior: TalkableRobot, fly_behavior: FlyableRobot): + self.walk_behavior = walk_behavior + self.talk_behavior = talk_behavior + self.fly_behavior = fly_behavior + + def walk(self): + self.walk_behavior.walk() + + def talk(self): + self.talk_behavior.talk() + + def fly(self): + self.fly_behavior.fly() + + @abstractmethod + def projection(self): + pass + +# --- Concrete Robot Types --- +class CompanionRobot(Robot): + def projection(self): + print("Displaying friendly companion features...") + +class WorkerRobot(Robot): + def projection(self): + print("Displaying worker efficiency stats...") + +# --- Main Function --- +if __name__ == "__main__": + robot1 = CompanionRobot(NormalWalk(), NormalTalk(), NoFly()) + robot1.walk() + robot1.talk() + robot1.fly() + robot1.projection() + + print("--------------------") + + robot2 = WorkerRobot(NoWalk(), NoTalk(), NormalFly()) + robot2.walk() + robot2.talk() + robot2.fly() + robot2.projection() \ No newline at end of file diff --git a/Lecture 09/Python Code/AbstractFactory.py b/Lecture 09/Python Code/AbstractFactory.py new file mode 100644 index 0000000..4b72bc2 --- /dev/null +++ b/Lecture 09/Python Code/AbstractFactory.py @@ -0,0 +1,122 @@ +from abc import ABC, abstractmethod + +# --- Product 1 --> Burger --- +class Burger(ABC): + @abstractmethod + def prepare(self): + pass + +class BasicBurger(Burger): + def prepare(self): + print("Preparing Basic Burger with bun, patty, and ketchup!") + +class StandardBurger(Burger): + def prepare(self): + print("Preparing Standard Burger with bun, patty, cheese, and lettuce!") + +class PremiumBurger(Burger): + def prepare(self): + print("Preparing Premium Burger with gourmet bun, premium patty, cheese, lettuce, and secret sauce!") + +class BasicWheatBurger(Burger): + def prepare(self): + print("Preparing Basic Wheat Burger with bun, patty, and ketchup!") + +class StandardWheatBurger(Burger): + def prepare(self): + print("Preparing Standard Wheat Burger with bun, patty, cheese, and lettuce!") + +class PremiumWheatBurger(Burger): + def prepare(self): + print("Preparing Premium Wheat Burger with gourmet bun, premium patty, cheese, lettuce, and secret sauce!") + +# --- Product 2 --> GarlicBread --- +class GarlicBread(ABC): + @abstractmethod + def prepare(self): + pass + +class BasicGarlicBread(GarlicBread): + def prepare(self): + print("Preparing Basic Garlic Bread with butter and garlic!") + +class CheeseGarlicBread(GarlicBread): + def prepare(self): + print("Preparing Cheese Garlic Bread with extra cheese and butter!") + +class BasicWheatGarlicBread(GarlicBread): + def prepare(self): + print("Preparing Basic Wheat Garlic Bread with butter and garlic!") + +class CheeseWheatGarlicBread(GarlicBread): + def prepare(self): + print("Preparing Cheese Wheat Garlic Bread with extra cheese and butter!") + +# --- Abstract Factory --- +class MealFactory(ABC): + @abstractmethod + def create_burger(self, type_): + pass + + @abstractmethod + def create_garlic_bread(self, type_): + pass + +# --- Concrete Factory 1 --- +class SinghBurger(MealFactory): + def create_burger(self, type_): + if type_.lower() == "basic": + return BasicBurger() + elif type_.lower() == "standard": + return StandardBurger() + elif type_.lower() == "premium": + return PremiumBurger() + else: + print("Invalid burger type!") + return None + + def create_garlic_bread(self, type_): + if type_.lower() == "basic": + return BasicGarlicBread() + elif type_.lower() == "cheese": + return CheeseGarlicBread() + else: + print("Invalid Garlic bread type!") + return None + +# --- Concrete Factory 2 --- +class KingBurger(MealFactory): + def create_burger(self, type_): + if type_.lower() == "basic": + return BasicWheatBurger() + elif type_.lower() == "standard": + return StandardWheatBurger() + elif type_.lower() == "premium": + return PremiumWheatBurger() + else: + print("Invalid burger type!") + return None + + def create_garlic_bread(self, type_): + if type_.lower() == "basic": + return BasicWheatGarlicBread() + elif type_.lower() == "cheese": + return CheeseWheatGarlicBread() + else: + print("Invalid Garlic bread type!") + return None + +# --- Main Section --- +if __name__ == "__main__": + burger_type = "basic" + garlic_bread_type = "cheese" + + meal_factory = SinghBurger() + + burger = meal_factory.create_burger(burger_type) + garlic_bread = meal_factory.create_garlic_bread(garlic_bread_type) + + if burger: + burger.prepare() + if garlic_bread: + garlic_bread.prepare() diff --git a/Lecture 09/Python Code/FactoryMethod.py b/Lecture 09/Python Code/FactoryMethod.py new file mode 100644 index 0000000..606c7c3 --- /dev/null +++ b/Lecture 09/Python Code/FactoryMethod.py @@ -0,0 +1,71 @@ +from abc import ABC, abstractmethod + +# Product Interface and subclasses +class Burger(ABC): + @abstractmethod + def prepare(self): + pass + +class BasicBurger(Burger): + def prepare(self): + print("Preparing Basic Burger with bun, patty, and ketchup!") + +class StandardBurger(Burger): + def prepare(self): + print("Preparing Standard Burger with bun, patty, cheese, and lettuce!") + +class PremiumBurger(Burger): + def prepare(self): + print("Preparing Premium Burger with gourmet bun, premium patty, cheese, lettuce, and secret sauce!") + +class BasicWheatBurger(Burger): + def prepare(self): + print("Preparing Basic Wheat Burger with bun, patty, and ketchup!") + +class StandardWheatBurger(Burger): + def prepare(self): + print("Preparing Standard Wheat Burger with bun, patty, cheese, and lettuce!") + +class PremiumWheatBurger(Burger): + def prepare(self): + print("Preparing Premium Wheat Burger with gourmet bun, premium patty, cheese, lettuce, and secret sauce!") + +# Factory Interface and Concrete Factories +class BurgerFactory(ABC): + @abstractmethod + def create_burger(self, type_): + pass + +class SinghBurger(BurgerFactory): + def create_burger(self, type_): + if type_.lower() == "basic": + return BasicBurger() + elif type_.lower() == "standard": + return StandardBurger() + elif type_.lower() == "premium": + return PremiumBurger() + else: + print("Invalid burger type!") + return None + +class KingBurger(BurgerFactory): + def create_burger(self, type_): + if type_.lower() == "basic": + return BasicWheatBurger() + elif type_.lower() == "standard": + return StandardWheatBurger() + elif type_.lower() == "premium": + return PremiumWheatBurger() + else: + print("Invalid burger type!") + return None + +# Main Section +if __name__ == "__main__": + type_ = "basic" + + my_factory = SinghBurger() + burger = my_factory.create_burger(type_) + + if burger: + burger.prepare() diff --git a/Lecture 09/Python Code/SimpleFactory.py b/Lecture 09/Python Code/SimpleFactory.py new file mode 100644 index 0000000..df39f52 --- /dev/null +++ b/Lecture 09/Python Code/SimpleFactory.py @@ -0,0 +1,44 @@ +from abc import ABC, abstractmethod + +# --- Burger Interface --- +class Burger(ABC): + @abstractmethod + def prepare(self): + pass + +# --- Concrete Burger Implementations --- +class BasicBurger(Burger): + def prepare(self): + print("Preparing Basic Burger with bun, patty, and ketchup!") + +class StandardBurger(Burger): + def prepare(self): + print("Preparing Standard Burger with bun, patty, cheese, and lettuce!") + +class PremiumBurger(Burger): + def prepare(self): + print("Preparing Premium Burger with gourmet bun, premium patty, cheese, lettuce, and secret sauce!") + +# --- Burger Factory --- +class BurgerFactory: + def create_burger(self, type_): + if type_.lower() == "basic": + return BasicBurger() + elif type_.lower() == "standard": + return StandardBurger() + elif type_.lower() == "premium": + return PremiumBurger() + else: + print("Invalid burger type!") + return None + +# --- Main Section --- +if __name__ == "__main__": + type_ = "standard" + + my_burger_factory = BurgerFactory() + + burger = my_burger_factory.create_burger(type_) + + if burger: + burger.prepare() diff --git a/Lecture 10/Python Code/NoSingleton.py b/Lecture 10/Python Code/NoSingleton.py new file mode 100644 index 0000000..13c7350 --- /dev/null +++ b/Lecture 10/Python Code/NoSingleton.py @@ -0,0 +1,9 @@ +class NoSingleton: + def __init__(self): + print("Singleton Constructor called. New Object created.") + +if __name__ == "__main__": + s1 = NoSingleton() + s2 = NoSingleton() + + print(s1 is s2) diff --git a/Lecture 10/Python Code/SimpleSingleton.py b/Lecture 10/Python Code/SimpleSingleton.py new file mode 100644 index 0000000..3c305d5 --- /dev/null +++ b/Lecture 10/Python Code/SimpleSingleton.py @@ -0,0 +1,18 @@ +class SimpleSingleton: + _instance = None + + def __init__(self): + print("Singleton Constructor called") + + @classmethod + def get_instance(cls): + if cls._instance is None: + cls._instance = SimpleSingleton() + return cls._instance + +if __name__ == "__main__": + s1 = SimpleSingleton.get_instance() + s2 = SimpleSingleton.get_instance() + + print(s1 is s2) + \ No newline at end of file diff --git a/Lecture 10/Python Code/ThreadSafeEagerSingleton.py b/Lecture 10/Python Code/ThreadSafeEagerSingleton.py new file mode 100644 index 0000000..2ad89ac --- /dev/null +++ b/Lecture 10/Python Code/ThreadSafeEagerSingleton.py @@ -0,0 +1,31 @@ +import threading + +class ThreadSafeLazySingleton: + _instance = None + _lock = threading.Lock() # A lock object to ensure thread safety + + def __init__(self): + if ThreadSafeLazySingleton._instance is not None: + raise RuntimeError("Use get_instance() instead") + print("Singleton Constructor Called!") + + @classmethod + def get_instance(cls): + if cls._instance is None: # First check (not locked) + with cls._lock: # Locking to ensure only one thread creates the instance + if cls._instance is None: # Second check (locked) + cls._instance = cls() + return cls._instance + +if __name__ == "__main__": + # Example usage + def create_singleton(): + singleton = ThreadSafeLazySingleton.get_instance() + print(f"Singleton instance: {singleton}") + + # Simulate multiple threads trying to access the singleton + threads = [threading.Thread(target=create_singleton) for _ in range(5)] + for thread in threads: + thread.start() + for thread in threads: + thread.join() \ No newline at end of file diff --git a/Lecture 11/Python Code/Tomato/Main.py b/Lecture 11/Python Code/Tomato/Main.py new file mode 100644 index 0000000..3ad7c4f --- /dev/null +++ b/Lecture 11/Python Code/Tomato/Main.py @@ -0,0 +1,24 @@ +from TomatoApp import TomatoApp +from models.User import User + +if __name__ == "__main__": + # Simulating a happy flow + tomato = TomatoApp() + + # Simulate a user coming in + user = User(101, "Aditya", "Delhi") + print(f"User: {user.get_name()} is active.") + + # User searches for restaurants by location + restaurant_list = tomato.search_restaurants("Delhi") + + if not restaurant_list: + print("No restaurants found!") + else: + print("Found Restaurants:") + for restaurant in restaurant_list: + print(f" - {restaurant.get_name()}") + + # User selects a restaurant + tomato.select_restaurant(user, restaurant_list[0]) + print(f"Selected restaurant: {restaurant_list[0].get_name()}") \ No newline at end of file diff --git a/Lecture 11/Python Code/Tomato/TomatoApp.py b/Lecture 11/Python Code/Tomato/TomatoApp.py new file mode 100644 index 0000000..406d75f --- /dev/null +++ b/Lecture 11/Python Code/Tomato/TomatoApp.py @@ -0,0 +1,85 @@ +from managers.RestaurantManager import RestaurantManager +from models.MenuItem import MenuItem +from models.Cart import Cart +from models.Order import Order +from models.User import User +from models.Restaurant import Restaurant +from factories.NowOrderFactory import NowOrderFactory +from factories.ScheduledOrderFactory import ScheduledOrderFactory +from services.NotificationService import NotificationService + + +class TomatoApp: + def __init__(self): + self.initialize_restaurants() + + def initialize_restaurants(self): + restaurant1 = Restaurant("Bikaner", "Delhi") + restaurant1.add_menu_item(MenuItem("P1", "Chole Bhature", 120)) + restaurant1.add_menu_item(MenuItem("P2", "Samosa", 15)) + + restaurant2 = Restaurant("Haldiram", "Kolkata") + restaurant2.add_menu_item(MenuItem("P1", "Raj Kachori", 80)) + restaurant2.add_menu_item(MenuItem("P2", "Pav Bhaji", 100)) + restaurant2.add_menu_item(MenuItem("P3", "Dhokla", 50)) + + restaurant3 = Restaurant("Saravana Bhavan", "Chennai") + restaurant3.add_menu_item(MenuItem("P1", "Masala Dosa", 90)) + restaurant3.add_menu_item(MenuItem("P2", "Idli Vada", 60)) + restaurant3.add_menu_item(MenuItem("P3", "Filter Coffee", 30)) + + restaurant_manager = RestaurantManager.get_instance() + restaurant_manager.add_restaurant(restaurant1) + restaurant_manager.add_restaurant(restaurant2) + restaurant_manager.add_restaurant(restaurant3) + + def search_restaurants(self, location): + return RestaurantManager.get_instance().search_by_location(location) + + def select_restaurant(self, user, restaurant): + cart = user.get_cart() + cart.set_restaurant(restaurant) + + def add_to_cart(self, user, item_code): + restaurant = user.get_cart().get_restaurant() + if restaurant is None: + print("Please select a restaurant first.") + return + for item in restaurant.get_menu(): + if item.get_code() == item_code: + user.get_cart().add_item(item) + break + + def checkout_now(self, user, order_type, payment_strategy): + return self.checkout(user, order_type, payment_strategy, NowOrderFactory()) + + def checkout_scheduled(self, user, order_type, payment_strategy, schedule_time): + return self.checkout(user, order_type, payment_strategy, ScheduledOrderFactory(schedule_time)) + + def checkout(self, user, order_type, payment_strategy, order_factory): + if user.get_cart().is_empty(): + return None + + user_cart = user.get_cart() + ordered_restaurant = user_cart.get_restaurant() + items_ordered = user_cart.get_items() + total_cost = user_cart.get_total_cost() + + order = order_factory.create_order(user, user_cart, ordered_restaurant, items_ordered, payment_strategy, total_cost, order_type) + RestaurantManager.get_instance().add_order(order) + return order + + def pay_for_order(self, user, order): + is_payment_success = order.process_payment() + + if is_payment_success: + NotificationService.notify(order) + user.get_cart().clear() + + def print_user_cart(self, user): + print("Items in cart:") + print("------------------------------------") + for item in user.get_cart().get_items(): + print(f"{item.get_code()} : {item.get_name()} : ₹{item.get_price()}") + print("------------------------------------") + print(f"Grand total : ₹{user.get_cart().get_total_cost()}") \ No newline at end of file diff --git a/Lecture 11/Python Code/Tomato/__pycache__/TomatoApp.cpython-313.pyc b/Lecture 11/Python Code/Tomato/__pycache__/TomatoApp.cpython-313.pyc new file mode 100644 index 0000000000000000000000000000000000000000..07489ce6e48a75089efdc456890b7714520b522c GIT binary patch literal 6078 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 PRfd^hwut_x@9O^mrs@9X literal 0 HcmV?d00001 diff --git a/Lecture 11/Python Code/Tomato/factories/NowOrderFactory.py b/Lecture 11/Python Code/Tomato/factories/NowOrderFactory.py new file mode 100644 index 0000000..ec42701 --- /dev/null +++ b/Lecture 11/Python Code/Tomato/factories/NowOrderFactory.py @@ -0,0 +1,7 @@ +from factories.OrderFactory import OrderFactory +from models.Order import Order + +class NowOrderFactory(OrderFactory): + def create_order(self, user, cart): + order = Order(user, cart.get_restaurant(), cart.get_items(), "Now") + return order \ No newline at end of file diff --git a/Lecture 11/Python Code/Tomato/factories/OrderFactory.py b/Lecture 11/Python Code/Tomato/factories/OrderFactory.py new file mode 100644 index 0000000..927fa53 --- /dev/null +++ b/Lecture 11/Python Code/Tomato/factories/OrderFactory.py @@ -0,0 +1,6 @@ +from abc import ABC, abstractmethod + +class OrderFactory(ABC): + @abstractmethod + def create_order(self, user, cart): + pass \ No newline at end of file diff --git a/Lecture 11/Python Code/Tomato/factories/ScheduledOrderFactory.py b/Lecture 11/Python Code/Tomato/factories/ScheduledOrderFactory.py new file mode 100644 index 0000000..4eff4eb --- /dev/null +++ b/Lecture 11/Python Code/Tomato/factories/ScheduledOrderFactory.py @@ -0,0 +1,7 @@ +from factories.OrderFactory import OrderFactory +from models.Order import Order + +class ScheduledOrderFactory(OrderFactory): + def create_order(self, user, cart, scheduled_time): + order = Order(user, cart.get_restaurant(), cart.get_items(), "Scheduled", scheduled_time) + return order \ No newline at end of file diff --git a/Lecture 11/Python Code/Tomato/factories/__pycache__/NowOrderFactory.cpython-313.pyc b/Lecture 11/Python Code/Tomato/factories/__pycache__/NowOrderFactory.cpython-313.pyc new file mode 100644 index 0000000000000000000000000000000000000000..0d9e0de04650bcd4fe3a34b2c91a7e3c8c6906ee GIT binary patch literal 850 zcmZ8fzi$&U6n;M6g;J%YKm#a>P=sK(rBQ({2z6=1&_*fh5mX6F)^TyuQ;q+E zLLIwwW@dwlm45+s09kZm>Vl9$ckH_ag}&i?@A-Q_?B_RLSeOSRzurIJqXgimb*AD? zjPZSA976yB*@O*(q+xAm)7hX%8*mHmKtO8{xQwjQA_v{R=aH5t*QZ(gHh(E8&Y z1IO@US{rt*ZO_K#!2qih-F3F7FP@xOHDv>`Y8x3zXqVmv-|1*-uHsX)=lV)tD2_s^ zFvBoW`m*(7C5F;>wJXJ7SG$=MsNE<;rM=XSMB3Db5iO!etZQh=WQL=VZ6%_G@oT|a zLhh^dfc1oo`w45eTdXZ2m7!>?tgxpewU;K1^|UA0vve4$l-xorS=P=%-ZStPek@jxdf)2Jul43hedXiB&ugF7P9Cg(>7FcZ9(vy^ONZsL z34{;O@k@G+^CTP!&hll`6n>6#$5CAh5=9iI2w1{^RG}^iAwf?J?dggXV6tTS65loAE-B9r(n$l9zK81@5}eT*i95|fnWbVygB*o_n%apuil0<4?I~z z3Mo5+Lx$`yz#xWQxC?1;2U0HBKJT>1=V8)2qaq0$fA;*qZL6uVs4~0M_N26fj5`auJgE{zibklw+T~-S8N5jW4`mg{w1~n{9@-TIP}JCiJj|IV5cI z6%y`3qZcz5)<&ZXGlkZWERJJ0%^r)_{@4gp<4TF+Qjf5Buf<54x3)SJxi-bT6yxzo zjCE#f)bZY)c)9ZbQ^p5XuEncrsca=?ZK^^WaWUk>)0G=$sFl^SqVVqarS`=Zr8ac& zAK}Mf*mweX)x#vY;s#QdYN@4kTT(8oyj~C=O8Kr7MWDmVll0)HeNvPc%2|3=$`}Kj@j|>3BL7i{0>+zYB=APvI#bsMJc+v%ainqLu9;x;I#TjGY;ohH+v*^pCzu>pl`#-`DqaFYN literal 0 HcmV?d00001 diff --git a/Lecture 11/Python Code/Tomato/factories/__pycache__/ScheduledOrderFactory.cpython-313.pyc b/Lecture 11/Python Code/Tomato/factories/__pycache__/ScheduledOrderFactory.cpython-313.pyc new file mode 100644 index 0000000000000000000000000000000000000000..a5771e98f57ddcfb8b5f40286b91006059e90929 GIT binary patch literal 896 zcmZuvJ#Q015Z%2GlSIx3Q4Gj3$ciYqCYAv=2)T(xkyr`xVT8y^%jLYbPqFX9>>iRk zDwLAO5+yAiRJ8mAkPFa?R8;AZOnP?je3p@z;_Zyy%+A}HovyB~AZ_oT_A3~nUr8_n zdv;FmDrbybo^c>$khuh&IVm+#hih(d=G?N4BkscV=jmp~OiT{AK zRX!&?hLJ}OL)L)c6(bGCPegP|I*bRskTjbO(qz7fft9OO@^~crQCQxMI*dGthMtH> zH`zkKIGKxHoa4^vNalTDo?tW)A-DgZx0s`K@;eG%qn{gvx1H~$%C}NwQmTHu|GECD zKDoF1<>+hc#bm=fvwy5_o#m%07kxknPEIaS8hS%Usa&CS80p0-KTqk)*c;54bxOMd za4`r%7Dkl9rYe^OO4WQt;8RZs2##aHxZ(B{onX?1;0&<@j0rTqg#J06Bph! KFOfQu{(k|tJmp#d literal 0 HcmV?d00001 diff --git a/Lecture 11/Python Code/Tomato/managers/OrderManager.py b/Lecture 11/Python Code/Tomato/managers/OrderManager.py new file mode 100644 index 0000000..cf8cd2c --- /dev/null +++ b/Lecture 11/Python Code/Tomato/managers/OrderManager.py @@ -0,0 +1,12 @@ +from services.NotificationService import NotificationService + +class OrderManager: + def __init__(self): + self.orders = [] + + def place_order(self, order): + self.orders.append(order) + NotificationService.notify(order) + + def get_orders(self): + return self.orders \ No newline at end of file diff --git a/Lecture 11/Python Code/Tomato/managers/RestaurantManager.py b/Lecture 11/Python Code/Tomato/managers/RestaurantManager.py new file mode 100644 index 0000000..3ea0500 --- /dev/null +++ b/Lecture 11/Python Code/Tomato/managers/RestaurantManager.py @@ -0,0 +1,18 @@ +class RestaurantManager: + _instance = None + + def __init__(self): + self.restaurants = [] + + @staticmethod + def get_instance(): + if RestaurantManager._instance is None: + RestaurantManager._instance = RestaurantManager() + return RestaurantManager._instance + + def add_restaurant(self, restaurant): + self.restaurants.append(restaurant) + + def search_by_location(self, location): + location = location.lower() + return [r for r in self.restaurants if r.get_location().lower() == location] \ No newline at end of file diff --git a/Lecture 11/Python Code/Tomato/managers/__pycache__/RestaurantManager.cpython-313.pyc b/Lecture 11/Python Code/Tomato/managers/__pycache__/RestaurantManager.cpython-313.pyc new file mode 100644 index 0000000000000000000000000000000000000000..2b754adde271e8f1e81bb2903557b12925a26c78 GIT binary patch literal 1599 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 MElY)S0w5Or3w7PE$p8QV literal 0 HcmV?d00001 diff --git a/Lecture 11/Python Code/Tomato/models/__pycache__/Restaurant.cpython-313.pyc b/Lecture 11/Python Code/Tomato/models/__pycache__/Restaurant.cpython-313.pyc new file mode 100644 index 0000000000000000000000000000000000000000..d02c2ea461400c5173c62b6fd144f4adac6fd4ac GIT binary patch literal 1810 zcmbtUOK;Oa5MC!vx=9lXZJ=&Mz#u9xh}QujRlosytP0c=Rl;axk|kI;PT6%3kwD^v zsA$D05@Pyd29RMUv@KpDT@ zDnN(aiPeNG#C{GGAlTYzz(wK@Y&+{OYk%2MBt)kCBsQ|N*B{)!WcmqDNp7nX zD>X0BXk`VikH!Q3BxGU`5A$kKaraaY+y;-R->kZ!*9;=P!Go5Sj&#ZW`yvOY2uzs7 z^Gwr>?p9}S@PR%YJa z+^k%Asehp5Pjq~XPQRzqZ})A|lOO4Hw`8p5x`w%0?3NC^)Yo!7*h;DcT492+N@W>@ z4$!#(|6j*3vaZdqYl;o{6~HcWqbVRyB%*a5GDYLC&xvvrmh^DTbJ87~c->xUZ%{+* z1x0mG5imhnIf9lBW*q+gQ72*?BrySCrPTGx6^VPy#0mK)ClcizSSd#Uz=@Kvmh0dD z4@4+WfCH=vQNmM)h$vvpgG!nlO5m_zAMV;A&^nXdVH0A4WNmkX4uI=hj zOfV|3jRbn7F1Pf4p>_?bFs34dK(+DR3qWz4)3m$q^=7yp0?zKWL8C&oBqkCvI*&c;wd=?KE%@2FF;sonFy5~g09MZngLpM*>On68L(pi_5@ Tf$%M@Y1)reS)1A>0BXZeN8@Se literal 0 HcmV?d00001 diff --git a/Lecture 11/Python Code/Tomato/models/__pycache__/User.cpython-313.pyc b/Lecture 11/Python Code/Tomato/models/__pycache__/User.cpython-313.pyc new file mode 100644 index 0000000000000000000000000000000000000000..d44d0e0d6036f6e16adb8d90c601f8087ea93628 GIT binary patch literal 1007 zcmbtTv2GJV5S_L6VkfaNkN{3V;Xo16H5Mt-AOuCC6kr9!5s1V|tK+h9PF(K7>>9}( z6#^-U0{IK5@;8*x2`Z{|C>Ek+=FUz5B~!ee+1;6W`{r)cY|a4L(wAp@_XWTY4kjkY z&S;sOA^6~nhwwn4aG?!1!LKZWUtO(~x3JQao^!&1Cvv$KqK(Rv5~+A$qg%8LApjIU zV8s_$`!YSXuT5rm$<#NktJgHJjG-1P4xF>IpHVB5WeLkVJv~4$;w1Vy1 z$(S9$i`wMI>e$(WM+t$K;I;+;nVn-m#Nb@3cw zUhiqE3aLs;laOT@H3*1OYwpwF!{BSZjTdO+e@JjaoFn*$0uN@a3RB>asp4e@ZtF=b zvUybH(0F{CUY%9t2au{WN|ECIg#Ct6ulr##K4~en8>6vFoa!`F3R_%eo}o>UUsB3g z`cNVjT8r_^zSTylqq23O6gqsFfkih==^dO_q;vJOA)JL@Qv?Ok;?Aa5&1cK$clb{# qKEJZWb*{td;{n_)Dc{2zw8xV%7YTk=g%IE2+HW~47EXbn$oT_XV$J^m literal 0 HcmV?d00001 diff --git a/Lecture 11/Python Code/Tomato/services/NotificationService.py b/Lecture 11/Python Code/Tomato/services/NotificationService.py new file mode 100644 index 0000000..5d92b87 --- /dev/null +++ b/Lecture 11/Python Code/Tomato/services/NotificationService.py @@ -0,0 +1,15 @@ +class NotificationService: + @staticmethod + def notify(order): + print(f"\nNotification: New {order.get_type()} order placed!") + print("---------------------------------------------") + print(f"Order ID: {order.get_order_id()}") + print(f"Customer: {order.get_user().get_name()}") + print(f"Restaurant: {order.get_restaurant().get_name()}") + print("Items Ordered:") + for item in order.get_items(): + print(f" - {item.get_name()} (₹{item.get_price()})") + print(f"Total: ₹{order.get_total()}") + print(f"Scheduled For: {order.get_scheduled()}") + print("Payment: Done") + print("---------------------------------------------") \ No newline at end of file diff --git a/Lecture 11/Python Code/Tomato/services/__pycache__/NotificationService.cpython-313.pyc b/Lecture 11/Python Code/Tomato/services/__pycache__/NotificationService.cpython-313.pyc new file mode 100644 index 0000000000000000000000000000000000000000..b3550e685d5f331411d96fe6ae5176b850d933e2 GIT binary patch literal 1799 zcmbVNL2nyH6rNpslZ|6w-o!M=ru&fpkzw!ty*HjqIa$Xt$QGQ*(8r$TxV1nUq1gGCx| z0|j7C2AG#Q98$tE9|yT%HWuU%o~VUWf;U&Th;hr%HDXw%jPPwkM}KoPPiM=%iPQRfJ))uIZ@y zRy+N_tR30#tFM;wupL=*Y+^MKrhar2*+g@&W)d1nR|#s^(9cEHd|QAJrlG^`C_MGY zSHE~%%3+`Jb&F{AJfu7A8Cl;#Ri}=s@QTG4W7o7+12MXiWujEX6PnmCi6_<&QAw+b zyeRYhr%{b+usCV}mO@F`?68&5gBlK$)6JGQVX{Hf^5Tc#0md}h9Gw+kg1^L=``Y5Y$`3cc zzu8^Nxr;0JO;@_y6R$j`h;*SR7N~PKvXkp4(w#)Qn^<<^XIv@M6W<>KdxhOXH}P&i zaki5<+fA&v@pG7tKDS5eY5CF7klC*zsEvPJn?A$ z__rJ1Y&@J_x>I@_oxOW`XK^pRoBnRuJ^s#*OZUSMq@ShknTzi7rC(>=BWn+%r6(b9 z^dwc!r0o@Vi`~R~ZanQur+eZuYdmvL=)-IWX1g%wo>+0Eb3O4q1@2fqal!9<;Wx1` zpl<^F1j?yNPgGTQ{;KLlRJCETYeoI2s($8Z^&v8&s<#Ymle%Fd(_%2az{JoSh#pfF z&r>q*sHz5=szwMlK5+=LRTaNMG5k7P*w>5MDEAjOv29lPHFzY