forked from faif/python-patterns
-
Notifications
You must be signed in to change notification settings - Fork 0
/
abstract_factory.py
151 lines (105 loc) · 3.26 KB
/
abstract_factory.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
#!/usr/bin/env python
# -*- coding: utf-8 -*-
"""
*What is this pattern about?
The Abstract Factory Pattern serves to provide an interface for
creating related/dependent objects without need to specify their
actual class.
The idea is to abstract the creation of objects depending on business
logic, platform choice, etc.
*What does this example do?
This particular implementation abstracts the creation of a pet and
does so depending on the AnimalFactory we chose (Dog or Cat)
This works because both Dog/Cat and their factories respect a common
interface (.speak(), get_pet() and get_food()).
Now my application can create pets (and feed them) abstractly and decide later,
based on my own criteria, dogs over cats.
The second example allows us to create pets based on the string passed by the
user, using cls.__subclasses__ (the list of sub classes for class cls)
and sub_cls.__name__ to get its name.
*Where is the pattern used practically?
*References:
https://sourcemaking.com/design_patterns/abstract_factory
http://ginstrom.com/scribbles/2007/10/08/design-patterns-python-style/
"""
import six
import abc
import random
class PetShop(object):
"""A pet shop"""
def __init__(self, animal_factory=None):
"""pet_factory is our abstract factory. We can set it at will."""
self.pet_factory = animal_factory
def show_pet(self):
"""Creates and shows a pet using the abstract factory"""
pet = self.pet_factory.get_pet()
print("We have a lovely {}".format(pet))
print("It says {}".format(pet.speak()))
print("We also have {}".format(self.pet_factory.get_food()))
# Stuff that our factory makes
class Dog(object):
def speak(self):
return "woof"
def __str__(self):
return "Dog"
class Cat(object):
def speak(self):
return "meow"
def __str__(self):
return "Cat"
# Factory classes
class DogFactory(object):
def get_pet(self):
return Dog()
def get_food(self):
return "dog food"
class CatFactory(object):
def get_pet(self):
return Cat()
def get_food(self):
return "cat food"
# Create the proper family
def get_factory():
"""Let's be dynamic!"""
return random.choice([DogFactory, CatFactory])()
# Implementation 2 of an abstract factory
@six.add_metaclass(abc.ABCMeta)
class Pet(object):
@classmethod
def from_name(cls, name):
for sub_cls in cls.__subclasses__():
if name == sub_cls.__name__.lower():
return sub_cls()
@abc.abstractmethod
def speak(self):
""""""
class Kitty(Pet):
def speak(self):
return "Miao"
class Duck(Pet):
def speak(self):
return "Quak"
# Show pets with various factories
if __name__ == "__main__":
for i in range(3):
shop = PetShop(get_factory())
shop.show_pet()
print("=" * 20)
for name0 in ["kitty", "duck"]:
pet = Pet.from_name(name0)
print("{}: {}".format(name0, pet.speak()))
### OUTPUT ###
# We have a lovely Cat
# It says meow
# We also have cat food
# ====================
# We have a lovely Dog
# It says woof
# We also have dog food
# ====================
# We have a lovely Cat
# It says meow
# We also have cat food
# ====================
# kitty: Miao
# duck: Quak