├── .gitignore ├── 01_inheritance ├── README.md └── main.py ├── 02_abstraction ├── README.md └── main.py ├── 03_composition ├── README.md └── main.py ├── 04_singleton ├── README.md └── main.py ├── 05_factory ├── README.md └── main.py ├── 06_observer ├── README.md └── main.py └── README.md /.gitignore: -------------------------------------------------------------------------------- 1 | .idea 2 | __pycache__ 3 | *.pyc 4 | -------------------------------------------------------------------------------- /01_inheritance/README.md: -------------------------------------------------------------------------------- 1 | ## Inheritance 2 | 3 | - when you have a child class that gets basic behavior from parent class 4 | - used to avoid rewriting common functions in every class that share similar behavior 5 | 6 | In this example, we have two types on enemies (Ninja and Zombie). Since all enemies share certain behaviors (moving 7 | left and right) we can write all of the common functionality inside one parent class instead of every enemy class. 8 | -------------------------------------------------------------------------------- /01_inheritance/main.py: -------------------------------------------------------------------------------- 1 | class Enemy(object): 2 | 3 | def move_left(self): 4 | print('Moving left...') 5 | 6 | def move_right(self): 7 | print('Moving right...') 8 | 9 | 10 | class Ninja(Enemy): 11 | 12 | def karate_chop(self): 13 | print('Karate chop!') 14 | 15 | 16 | class Zombie(Enemy): 17 | 18 | def bite(self): 19 | print('I am biting you!') 20 | 21 | 22 | enemy = Enemy() 23 | enemy.move_left() 24 | 25 | # Ninja also includes all functions from parent class (Enemy) 26 | ninja = Ninja() 27 | ninja.move_left() 28 | ninja.karate_chop() 29 | 30 | # Zombie is called (the child class), inherits from Enemy (parent class) 31 | zombie = Zombie() 32 | zombie.move_right() 33 | zombie.bite() 34 | -------------------------------------------------------------------------------- /02_abstraction/README.md: -------------------------------------------------------------------------------- 1 | ## Abstraction 2 | 3 | - a way that you can provide a simple interface for users while hiding the complexity 4 | 5 | To use a microwave, you don't need to know how electromagnetic waves or electronics work. The user is provided a simple 6 | interface (buttons) that they can easily use. 7 | -------------------------------------------------------------------------------- /02_abstraction/main.py: -------------------------------------------------------------------------------- 1 | class Rectangle(object): 2 | 3 | @staticmethod 4 | def calculate_area(width, height): 5 | return width * height 6 | 7 | 8 | # User does not need to know formula to get area of Rectangle 9 | area = Rectangle.calculate_area(5, 7) 10 | print(area) 11 | -------------------------------------------------------------------------------- /03_composition/README.md: -------------------------------------------------------------------------------- 1 | ## Composition 2 | 3 | - when you have objects made up of other objects 4 | - used to create complex objects by putting together simple objects 5 | 6 | In this example, we can compose a Person object by combining a Head and a Body class. 7 | -------------------------------------------------------------------------------- /03_composition/main.py: -------------------------------------------------------------------------------- 1 | class Head(object): 2 | 3 | def __init__(self, eye_color, hair_color): 4 | self.eye_color = eye_color 5 | self.hair_color = hair_color 6 | 7 | 8 | class Body(object): 9 | 10 | def __init__(self, weight): 11 | self.weight = weight 12 | 13 | 14 | class Person(object): 15 | 16 | def __init__(self, eye_color, hair_color, weight): 17 | self.head = Head(eye_color, hair_color) 18 | self.body = Body(weight) 19 | 20 | def print_eye_color(self): 21 | print(self.head.eye_color) 22 | 23 | bucky = Person('blue', 'blonde', 160) 24 | bucky.print_eye_color() 25 | -------------------------------------------------------------------------------- /04_singleton/README.md: -------------------------------------------------------------------------------- 1 | ## Singleton 2 | 3 | The singleton pattern is used to ensure one and only one object from a class gets created. 4 | -------------------------------------------------------------------------------- /04_singleton/main.py: -------------------------------------------------------------------------------- 1 | class Singleton(object): 2 | __instance = None 3 | 4 | def __init__(self): 5 | if not Singleton.__instance: 6 | print('Instance does not exist...') 7 | else: 8 | print('Instance exists:', self.get_instance()) 9 | 10 | @classmethod 11 | def get_instance(cls): 12 | if not cls.__instance: 13 | cls.__instance = Singleton() 14 | return cls.__instance 15 | 16 | a = Singleton() 17 | 18 | # Once a singleton is created, all instances of this class will use the same object 19 | print('Creating instance', Singleton.get_instance()) 20 | 21 | # Since singleton already created, the existing object is returned 22 | b = Singleton() 23 | 24 | # Even though we now have 3 different instances of this class, they all reference the same object 25 | c = Singleton() 26 | -------------------------------------------------------------------------------- /05_factory/README.md: -------------------------------------------------------------------------------- 1 | ## Factory 2 | 3 | - A factory is a class that is responsible for creating objects of other types. 4 | - For example, if we were making a game and we wanted to generate different enemies randomly at runtime, we could use a 5 | factory pattern to generate these objects dynamically (all must share the same parent class "Enemy") 6 | - Used when you don't know ahead of time what class object you need 7 | -------------------------------------------------------------------------------- /05_factory/main.py: -------------------------------------------------------------------------------- 1 | from random import randrange 2 | 3 | 4 | class Weapon(object): 5 | name = None 6 | cost = None 7 | 8 | @staticmethod 9 | def get_weapon(x): 10 | if x == 0: 11 | return Knife() 12 | if x == 1: 13 | return Gun() 14 | 15 | 16 | class Knife(Weapon): 17 | name = 'Knife' 18 | cost = 20.00 19 | 20 | 21 | class Gun(Weapon): 22 | name = 'Gun' 23 | cost = 300.00 24 | 25 | 26 | # Create 25 random weapons 27 | for _ in range(25): 28 | w = Weapon.get_weapon(randrange(2)) 29 | print(w.name, w.cost) 30 | -------------------------------------------------------------------------------- /06_observer/README.md: -------------------------------------------------------------------------------- 1 | ## Observer 2 | 3 | Used when you need many objects to update when another object changes 4 | 5 | -------------------------------------------------------------------------------- /06_observer/main.py: -------------------------------------------------------------------------------- 1 | class Publisher(object): 2 | users = set() 3 | 4 | def register(self, user): 5 | self.users.add(user) 6 | 7 | def unregister(self, user): 8 | self.users.discard(user) 9 | 10 | def send_notifications(self, message): 11 | for user in self.users: 12 | user.notify(message) 13 | 14 | 15 | class Subscriber(object): 16 | 17 | def __init__(self, username): 18 | self.username = username 19 | 20 | def notify(self, message): 21 | print(self.username + ' received message: ' + message) 22 | 23 | publisher = Publisher() 24 | 25 | # Create observers that will receive notifications 26 | bucky = Subscriber('Bucky') 27 | sally = Subscriber('Sally') 28 | publisher.register(bucky) 29 | publisher.register(sally) 30 | 31 | # Notifications are sent to every observer (subscriber) 32 | publisher.send_notifications('We updated the website') 33 | publisher.send_notifications('Make sure to add a profile picture') 34 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ## Python Design Patterns 2 | 3 | Here is an overview of several different design patterns and concepts in Python. 4 | --------------------------------------------------------------------------------