├── .DS_Store ├── README.md ├── __pycache__ └── abstract_factory.cpython-38.pyc ├── abstract_factory.py ├── adapter.py ├── decorator.py ├── factory.py ├── observer ├── decorators.py ├── main.py ├── notification.py └── shop.py ├── prototype.py ├── proxy-dic.py ├── proxy-lazy.py ├── proxy.py ├── singleton.py ├── state.py └── strategy.py /.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fatighasemi74/DesignPatterns/4a7c5a48d853a05d08eb514e33e0edcaeb912c48/.DS_Store -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # DesignPatterns -------------------------------------------------------------------------------- /__pycache__/abstract_factory.cpython-38.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/fatighasemi74/DesignPatterns/4a7c5a48d853a05d08eb514e33e0edcaeb912c48/__pycache__/abstract_factory.cpython-38.pyc -------------------------------------------------------------------------------- /abstract_factory.py: -------------------------------------------------------------------------------- 1 | from abc import ABC, abstractmethod 2 | 3 | 4 | class ProductBase(ABC): 5 | @abstractmethod 6 | def detail(self): 7 | pass 8 | 9 | @abstractmethod 10 | def price(self): 11 | pass 12 | 13 | 14 | class DetailBase(ABC): 15 | @abstractmethod 16 | def show(self): 17 | pass 18 | 19 | class RugsDetail(DetailBase): 20 | 21 | def __init__(self, rugs): 22 | self.rugs = rugs 23 | 24 | def show(self): 25 | return f"rugs detail: {self.rugs._name}" 26 | 27 | class RugsPrice(DetailBase): 28 | 29 | def __init__(self, rugs): 30 | self.rugs = rugs 31 | 32 | 33 | def show(self): 34 | return f"rugs price: {self.rugs._price}$" 35 | 36 | class GiftCardDetail(DetailBase): 37 | 38 | def __init__(self, card): 39 | self.card = card 40 | 41 | def show(self): 42 | return f"company: {self.card.company}" 43 | 44 | 45 | class GiftCardPrice(DetailBase): 46 | def __init__(self, card): 47 | self.card = card 48 | 49 | def show(self): 50 | return f"gift card min price: {self.card.min_price}\tmax price: {self.card.max_price}\t" 51 | 52 | class Rugs(ProductBase): 53 | 54 | def __init__(self, name, price): 55 | self._name = name 56 | self._price = price 57 | 58 | @property 59 | def detail(self): 60 | return RugsDetail(self) 61 | 62 | @property 63 | def price(self): 64 | return RugsPrice(self) 65 | 66 | 67 | class GiftCard(ProductBase): 68 | 69 | def __init__(self, company, min_price, max_price): 70 | self.company = company 71 | self.min_price = min_price 72 | self.max_price = max_price 73 | 74 | @property 75 | def detail(self): 76 | return GiftCardDetail(self) 77 | 78 | @property 79 | def price(self): 80 | return GiftCardPrice(self) 81 | 82 | 83 | 84 | 85 | if __name__ == "__main__": 86 | r1 = Rugs('persian rugs', 135) 87 | r2 = Rugs('nain rugs', 150) 88 | 89 | g1 = GiftCard('google', 20, 60) 90 | g2 = GiftCard('apple', 20, 60) 91 | 92 | products = [r1, r2, g1, g2] 93 | 94 | for product in products: 95 | print(product.detail.show()) 96 | print(product.price.show()) -------------------------------------------------------------------------------- /adapter.py: -------------------------------------------------------------------------------- 1 | from abstract_factory import Rugs 2 | 3 | class PriceAdapter: 4 | def __init__(self, rate): 5 | self.rate = rate 6 | 7 | def exchange(self, product): 8 | return self.rate * product._price 9 | 10 | if __name__ == "__main__": 11 | r1 = Rugs('persian rugs', 20) 12 | r2 = Rugs('nain rugs', 23) 13 | r3 = Rugs('morrocco rugs', 19) 14 | 15 | adapter =PriceAdapter(rate=28000) 16 | 17 | rugs = [r1, r2, r3] 18 | 19 | for rug in rugs: 20 | print(f"{rug._name}: {adapter.exchange(rug)}") -------------------------------------------------------------------------------- /decorator.py: -------------------------------------------------------------------------------- 1 | COUNTRIES = ['Iran', 'UAE'] 2 | VAT = {"Iran": 9, "UAE": 15} # Value added tax 3 | 4 | class User: 5 | pass 6 | 7 | class Address: 8 | def __init__(self, country): 9 | self.country = country 10 | 11 | class Product: 12 | def __init__(self, name, price): 13 | self.name = name 14 | self.price = price 15 | 16 | class Purchase: 17 | def __init__(self, user, address): 18 | self.user = user 19 | self.address = address 20 | self.products_list = [] 21 | 22 | def add_products(self, products_list): 23 | if not isinstance(products_list, list): 24 | products_list = [products_list] 25 | self.products_list.extend(products_list) 26 | 27 | def total_price(self): 28 | s = 0 29 | for product in self.products_list: 30 | s += product.price 31 | return s 32 | 33 | def calculate_vat(func): 34 | def wrapped_func(pur): 35 | vat = VAT[pur.address.country] 36 | total_price = pur.total_price() 37 | return total_price + total_price * vat / 100 38 | 39 | 40 | return wrapped_func 41 | 42 | def show_total_price(p): 43 | return p.total_price() 44 | 45 | @calculate_vat 46 | def show_vat_pluse_price(p): 47 | return p.total_price() 48 | 49 | if __name__ == "__main__": 50 | user = User() 51 | addr_iran = Address(country=COUNTRIES[0]) 52 | addr_uae = Address(country=COUNTRIES[1]) 53 | p1 = Product("persian rugs", 120) 54 | p2 = Product("nain rugs", 145) 55 | p3 = Product("galaxy rugs", 105) 56 | 57 | products = [p1, p2, p3] 58 | 59 | purchase_iran = Purchase(user=user, address=addr_iran) 60 | purchase_iran.add_products(p1) 61 | purchase_iran.add_products([p2, p3]) 62 | print(show_total_price(purchase_iran)) 63 | print(show_vat_pluse_price(purchase_iran)) 64 | 65 | 66 | purchase_uae = Purchase(user=user, address=addr_uae) 67 | purchase_uae.add_products(p1) 68 | purchase_uae.add_products([p2, p3]) 69 | print(show_total_price(purchase_uae)) 70 | print(show_vat_pluse_price(purchase_uae)) -------------------------------------------------------------------------------- /factory.py: -------------------------------------------------------------------------------- 1 | from abc import ABC, abstractmethod 2 | from random import choice 3 | 4 | class PlayerBase(ABC): 5 | choices = ['r', 'p', 's'] 6 | 7 | @abstractmethod 8 | def move(self): 9 | pass 10 | 11 | class HumanPlayer(PlayerBase): 12 | def move(self): 13 | m = input('choose your next move...') 14 | return m 15 | 16 | class SystemPlayer(PlayerBase): 17 | def move(self): 18 | return choice(self.choices) 19 | 20 | class Game: 21 | @staticmethod 22 | def start_game(): 23 | game_type = input("please choose game type('s' for single and 'm' for multiple player):") 24 | if game_type == 's': 25 | p1 = HumanPlayer() 26 | p2 = SystemPlayer() 27 | elif game_type == 'm': 28 | p1 = HumanPlayer() 29 | p2 = HumanPlayer() 30 | else: 31 | print("Invalid input") 32 | p1 = None 33 | p2 = None 34 | return p1, p2 35 | 36 | if __name__ == "__main__": 37 | player_1, player_2 = Game.start_game() 38 | 39 | for player in [player_1, player_2]: 40 | player.move() -------------------------------------------------------------------------------- /observer/decorators.py: -------------------------------------------------------------------------------- 1 | def notify_observers(message=''): 2 | def decorated_method(func): 3 | def wrapped(obj, *args, **kwargs): 4 | result = func(obj, *args, **kwargs) 5 | for observer in obj.observers: 6 | observer.send(message) 7 | return result 8 | 9 | return decorated_method -------------------------------------------------------------------------------- /observer/main.py: -------------------------------------------------------------------------------- 1 | from observer.shop import Product, Purchase 2 | 3 | if __name__ == "__main__": 4 | p1 = Product() 5 | p2 = Product() 6 | p3 = Product() 7 | p4 = Product() 8 | 9 | purchase = Purchase([p1, p2, p3, p4]) 10 | purchase.checkout() 11 | purchase.cancel() -------------------------------------------------------------------------------- /observer/notification.py: -------------------------------------------------------------------------------- 1 | from abc import ABC, abstractmethod 2 | 3 | class Observer(ABC): 4 | @staticmethod 5 | @abstractmethod 6 | def send(message=''): 7 | pass 8 | 9 | class EmailNotification(Observer): 10 | @staticmethod 11 | def send(cls, message=''): 12 | print(f"Sending email message {message}") 13 | 14 | class SMSNotification(Observer): 15 | @staticmethod 16 | def send(message=''): 17 | print(f"send sms message {message}") 18 | 19 | class PushNotification(Observer): 20 | @staticmethod 21 | def send(message=''): 22 | print(f"send push notification {message}") -------------------------------------------------------------------------------- /observer/shop.py: -------------------------------------------------------------------------------- 1 | from observer.decorators import notify_observers 2 | from observer.notification import EmailNotification, SMSNotification, PushNotification 3 | 4 | class Product: 5 | pass 6 | 7 | class Payment: 8 | observers = [PushNotification, SMSNotification] 9 | 10 | @notify_observers(message="purchase paid") 11 | def checkout(self): 12 | pass 13 | 14 | class Purchase: 15 | observer = [EmailNotification, SMSNotification, PushNotification] 16 | 17 | def __init__(self, product_list): 18 | self.product = product_list 19 | self.payment = Payment() 20 | 21 | def checkout(self): 22 | self.payment.checkout() 23 | 24 | @notify_observers(message="purchase canceled") 25 | def cancel(self): 26 | pass -------------------------------------------------------------------------------- /prototype.py: -------------------------------------------------------------------------------- 1 | class Cinema: 2 | pass 3 | 4 | class Movie: 5 | pass 6 | 7 | class Time: 8 | pass 9 | 10 | class Hall: 11 | def __init__(self, name, cinema, capacity): 12 | self.cinema = cinema 13 | self.capacity = capacity 14 | self.name = name 15 | 16 | class Seat: 17 | def __init__(self, number, status): 18 | self.number = number 19 | self.status = None 20 | 21 | class Sens: 22 | def __init__(self, cinema, movie, time, hall): 23 | self.cinema = cinema 24 | self.movie = movie 25 | self.time = time 26 | self.hall = hall 27 | self.seats = list() 28 | self.prototype_seats() 29 | 30 | def prototype_seats(self): 31 | """ Prototype all seats of selected hall """ 32 | for i in range(self.hall.capacity): 33 | self.seats.append(Seat(i)) 34 | 35 | 36 | if __name__ == "__main__": 37 | cinema = Cinema() 38 | movie = Movie() 39 | time = Time() 40 | hall = Hall('hall name', cinema, 60) 41 | 42 | sens = Sens(cinema, movie, time, hall) 43 | print(len(sens.seats)) 44 | print(type(sens.seats[0])) 45 | -------------------------------------------------------------------------------- /proxy-dic.py: -------------------------------------------------------------------------------- 1 | import random 2 | 3 | class User: 4 | pass 5 | 6 | 7 | class Dice: 8 | @staticmethod 9 | def roll(): 10 | return random.randint(1, 6) 11 | 12 | class Game: 13 | def __init__(self, u1, u2): 14 | self.user1 = u1 15 | self.user2 = u2 16 | self.turn = u1 17 | self.dice = Dice 18 | 19 | def change_turn(self): 20 | self.turn = self.user2 if self.turn == self.user1 else self.user2 21 | 22 | def check_turn_and_roll_dice(game, user): 23 | if game.turn == user: 24 | game.change_turn() 25 | return game.dice.roll() 26 | return "it is not your turn." 27 | 28 | 29 | if __name__ == "__main__": 30 | user1 = User() 31 | user2 = User() 32 | 33 | game = Game(user1, user2) 34 | 35 | # print(game.roll_dice(user1)) 36 | # print(game.roll_dice(user1)) 37 | # print(game.roll_dice(user2)) 38 | # print(game.roll_dice(user2)) 39 | # print(game.roll_dice(user1)) 40 | # print(game.roll_dice(user2)) 41 | 42 | print(check_turn_and_roll_dice(game, user1)) 43 | print(check_turn_and_roll_dice(game, user1)) 44 | print(check_turn_and_roll_dice(game, user1)) 45 | print(check_turn_and_roll_dice(game, user2)) -------------------------------------------------------------------------------- /proxy-lazy.py: -------------------------------------------------------------------------------- 1 | from time import sleep 2 | 3 | class LazyLoader: 4 | def __init__(self, cls): 5 | self.cls = cls 6 | self.object = None 7 | 8 | def __getattr__(self, item): 9 | if self.object is None: 10 | self.object = self.cls() 11 | return getattr(self.object, item) 12 | 13 | class MySQLHandler: 14 | def __init__(self): 15 | sleep(1) 16 | 17 | def get(self): 18 | return "Hello from MySQL" 19 | 20 | class MongoHandler: 21 | def __init__(self): 22 | sleep(100) 23 | 24 | def get(self): 25 | return "Hello from Mongo" 26 | 27 | class NotificationCenterHandler: 28 | def __init__(self): 29 | sleep(3) 30 | 31 | def get(self): 32 | return "Hello from Notif Center" 33 | 34 | if __name__ == "__main__": 35 | mysql = LazyLoader(MySQLHandler) 36 | mongo = LazyLoader(MongoHandler) 37 | notif = LazyLoader(NotificationCenterHandler) 38 | 39 | 40 | print(mysql.get()) 41 | print(notif.get()) 42 | print(mongo.get()) -------------------------------------------------------------------------------- /proxy.py: -------------------------------------------------------------------------------- 1 | COUNTRIES = ['Iran', 'UAE'] 2 | VAT = {"Iran": 9, "UAE": 15} # Value added tax 3 | 4 | 5 | def check_permission(func): #proxy 6 | def wrapped_func(obj, user): 7 | if obj.user == user: 8 | return func(obj) 9 | return "you are not allowed to checkout" 10 | return wrapped_func 11 | 12 | class User: 13 | pass 14 | 15 | class Address: 16 | def __init__(self, country): 17 | self.country = country 18 | 19 | class Product: 20 | def __init__(self, name, price): 21 | self.name = name 22 | self.price = price 23 | 24 | class Purchase: 25 | def __init__(self, user, address): 26 | self.user = user 27 | self.address = address 28 | self.products_list = [] 29 | 30 | def add_products(self, products_list): 31 | if not isinstance(products_list, list): 32 | products_list = [products_list] 33 | self.products_list.extend(products_list) 34 | 35 | def total_price(self): 36 | s = 0 37 | for product in self.products_list: 38 | s += product.price 39 | return s 40 | 41 | @check_permission 42 | def checkout(self): 43 | return "checkout done!" 44 | 45 | def calculate_vat(func): #decorator 46 | def wrapped_func(pur): 47 | vat = VAT[pur.address.country] 48 | total_price = pur.total_price() 49 | return total_price + total_price * vat / 100 50 | 51 | 52 | return wrapped_func 53 | 54 | def show_total_price(p): 55 | return p.total_price() 56 | 57 | @calculate_vat 58 | def show_vat_pluse_price(p): 59 | return p.total_price() 60 | 61 | if __name__ == "__main__": 62 | user = User() 63 | addr_iran = Address(country=COUNTRIES[0]) 64 | addr_uae = Address(country=COUNTRIES[1]) 65 | p1 = Product("persian rugs", 120) 66 | p2 = Product("nain rugs", 145) 67 | p3 = Product("galaxy rugs", 105) 68 | 69 | products = [p1, p2, p3] 70 | 71 | purchase_iran = Purchase(user=user, address=addr_iran) 72 | purchase_iran.add_products(p1) 73 | purchase_iran.add_products([p2, p3]) 74 | # print(show_total_price(purchase_iran)) 75 | # print(show_vat_pluse_price(purchase_iran)) 76 | 77 | 78 | purchase_uae = Purchase(user=user, address=addr_uae) 79 | purchase_uae.add_products(p1) 80 | purchase_uae.add_products([p2, p3]) 81 | # print(show_total_price(purchase_uae)) 82 | # print(show_vat_pluse_price(purchase_uae)) 83 | 84 | u1 = User() 85 | print(purchase_iran.checkout(user)) 86 | print(purchase_uae.checkout(u1)) -------------------------------------------------------------------------------- /singleton.py: -------------------------------------------------------------------------------- 1 | class Singleton: 2 | 3 | @classmethod 4 | def __new__(cls, *args, **kwargs): 5 | if not hasattr(cls, 'instance'): 6 | cls.instance = super(*args, **kwargs) 7 | return cls.instance 8 | 9 | 10 | if __name__ == "__main__": 11 | s1 = Singleton() 12 | s2 = Singleton() 13 | s3 = Singleton() 14 | 15 | 16 | print(id(s1)) 17 | print(id(s2)) 18 | print(id(s3)) 19 | 20 | print(id(s1) == id(s2) == id(s3)) -------------------------------------------------------------------------------- /state.py: -------------------------------------------------------------------------------- 1 | from abc import ABC, abstractmethod 2 | 3 | class Message: 4 | def __init__(self, subject, body, sender): 5 | self.subject = subject 6 | self.body = body 7 | self.sender = sender 8 | self.flow = [sender] 9 | 10 | @property 11 | def current(self): 12 | return self.flow[-1] 13 | 14 | def send(self, to_user): 15 | if to_user.__class__ not in self.current.allowed: 16 | print(f"{self.current.__class__} is not allowed to send email to {to_user.__class__}") 17 | else: 18 | print(f"message sent to {to_user.__class__}") 19 | 20 | 21 | class AbstractUser(ABC): 22 | @property 23 | @abstractmethod 24 | def allowed(self): 25 | pass 26 | 27 | class ManagingDirector(AbstractUser): 28 | allowed = [] 29 | 30 | class InternalManager(AbstractUser): 31 | allowed = [ManagingDirector] 32 | 33 | class Supervisor(AbstractUser): 34 | allowed = [InternalManager] 35 | 36 | class Operator(AbstractUser): 37 | allowed = [Supervisor] 38 | 39 | class Client(AbstractUser): 40 | allowed = [Operator] 41 | 42 | if __name__ == "__main__": 43 | opt = Operator() 44 | spr = Supervisor() 45 | inm = InternalManager() 46 | mnd = ManagingDirector() 47 | 48 | client = Client() 49 | message = Message("Issue #1234", "Issue description", client) 50 | 51 | message.send(opt) 52 | message.send(inm) 53 | message.send(spr) 54 | message.send(client) 55 | message.send(inm) 56 | message.send(mnd) 57 | 58 | -------------------------------------------------------------------------------- /strategy.py: -------------------------------------------------------------------------------- 1 | class Product: 2 | def __init__(self, name, price): 3 | self.name = name 4 | self.price = price 5 | 6 | class Gateway: 7 | def __init__(self, name): 8 | self.name = name 9 | 10 | class Payment: 11 | gateways = (Gateway("G1"), Gateway("G2")) 12 | def __init__(self, purchase): 13 | self.purchase = purchase 14 | 15 | def get_gateway(self): 16 | return self.gateways[0] if self.purchase.total_price() < 100 else self.gateways[1] 17 | 18 | def pay(self): 19 | """ if payment amount is less than 100, 20 | use G1 gateway otherwise use G2 """ 21 | gateway = self.get_gateway() 22 | print(f"Payment is being paid through {gateway.name}") 23 | 24 | class Purchase: 25 | def __init__(self): 26 | self.products = list() 27 | self.payment = Payment(self) 28 | 29 | def add(self, product): 30 | self.products.append(product) 31 | 32 | def total_price(self): 33 | return sum([p.price for p in self.products]) 34 | 35 | def checkout(self): 36 | self.payment.pay() 37 | 38 | if __name__ == "__main__": 39 | p1 = Product('p1', 40) 40 | p2 = Product('p2', 30) 41 | p3 = Product('p3', 50) 42 | 43 | purchase = Purchase() 44 | 45 | purchase.add(p1) 46 | print(purchase.total_price()) 47 | purchase.checkout() 48 | 49 | purchase.add(p2) 50 | print(purchase.total_price()) 51 | purchase.checkout() 52 | 53 | 54 | purchase.add(p3) 55 | print(purchase.total_price()) 56 | purchase.checkout() 57 | --------------------------------------------------------------------------------