forked from faif/python-patterns
-
Notifications
You must be signed in to change notification settings - Fork 0
/
abstract_factory.py
107 lines (77 loc) · 2.59 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
"""
*What is this pattern about?
In Java and other languages, 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.
In Python, the interface we use is simply a callable, which is "builtin" interface
in Python, and in normal circumstances we can simply use the class itself as
that callable, because classes are first class objects in Python.
*What does this example do?
This particular implementation abstracts the creation of a pet and
does so depending on the factory we chose (Dog or Cat, or random_animal)
This works because both Dog/Cat and random_animal respect a common
interface (callable for creation and .speak()).
Now my application can create pets abstractly and decide later,
based on my own criteria, dogs over cats.
*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/
*TL;DR
Provides a way to encapsulate a group of individual factories.
"""
import random
class PetShop:
"""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()
print("We have a lovely {}".format(pet))
print("It says {}".format(pet.speak()))
class Dog:
def speak(self):
return "woof"
def __str__(self):
return "Dog"
class Cat:
def speak(self):
return "meow"
def __str__(self):
return "Cat"
# Additional factories:
# Create a random animal
def random_animal():
"""Let's be dynamic!"""
return random.choice([Dog, Cat])()
# Show pets with various factories
def main():
"""
# A Shop that sells only cats
>>> cat_shop = PetShop(Cat)
>>> cat_shop.show_pet()
We have a lovely Cat
It says meow
# A shop that sells random animals
>>> shop = PetShop(random_animal)
>>> for i in range(3):
... shop.show_pet()
... print("=" * 20)
We have a lovely Cat
It says meow
====================
We have a lovely Dog
It says woof
====================
We have a lovely Dog
It says woof
====================
"""
if __name__ == "__main__":
random.seed(1234) # for deterministic doctest outputs
import doctest
doctest.testmod()