Skip to content

Commit 640cf76

Browse files
committed
Merge pull request faif#1 from faif/master
Update from original
2 parents 11b4b6a + c10a94e commit 640cf76

37 files changed

+773
-327
lines changed

‎.gitignore‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
__pycache__

‎3-tier.py‎

Lines changed: 26 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3,35 +3,43 @@
33

44

55
classData(object):
6+
""" Data Store Class """
67

78
products={
89
'milk':{'price': 1.50, 'quantity': 10},
910
'eggs':{'price': 0.20, 'quantity': 100},
1011
'cheese':{'price': 2.00, 'quantity': 10}
1112
}
1213

14+
def__get__(self, obj, klas):
15+
print ("(Fetching from Data Store)")
16+
return{'products': self.products}
17+
1318

1419
classBusinessLogic(object):
1520

16-
def__init__(self):
17-
self.data=Data()
21+
""" Business logic holding data store instances """
22+
23+
data=Data()
1824

1925
defproduct_list(self):
20-
returnself.data.products.keys()
26+
returnself.data['products'].keys()
2127

2228
defproduct_information(self, product):
23-
returnself.data.products.get(product, None)
29+
returnself.data['products'].get(product, None)
2430

2531

2632
classUi(object):
33+
""" UI interaction class """
2734

2835
def__init__(self):
2936
self.business_logic=BusinessLogic()
3037

3138
defget_product_list(self):
3239
print('PRODUCT LIST:')
3340
forproductinself.business_logic.product_list():
34-
print(product)
41+
#print(product)
42+
yieldproduct
3543
print('')
3644

3745
defget_product_information(self, product):
@@ -56,3 +64,16 @@ def main():
5664

5765
if__name__=='__main__':
5866
main()
67+
68+
### OUTPUT ###
69+
# (Fetching from Data Store)
70+
# PRODUCT INFORMATION:
71+
# Name: Cheese, Price: 2.00, Quantity: 10
72+
# (Fetching from Data Store)
73+
# PRODUCT INFORMATION:
74+
# Name: Eggs, Price: 0.20, Quantity: 100
75+
# (Fetching from Data Store)
76+
# PRODUCT INFORMATION:
77+
# Name: Milk, Price: 1.50, Quantity: 10
78+
# (Fetching from Data Store)
79+
# That product "arepas" does not exist in the records

‎README.md‎

Lines changed: 35 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -1,34 +1,41 @@
11
python-patterns
22
===============
33

4-
A collection of design patterns implemented (by other people) in python
4+
A collection of design patterns and idioms in Python.
5+
6+
When an implementation is added or modified, be sure to update this file and
7+
rerun `append_output.sh` (eg. ./append_output.sh borg.py) to keep the output
8+
comments at the bottom up to date.
59

610
Current Patterns:
711

8-
* 3-tier
9-
* composite
10-
* mvc
11-
* decorator
12-
* null
13-
* facade
14-
* observer
15-
* abstract_factory
16-
* factory_method
17-
* pool
18-
* adapter
19-
* flyweight
20-
* prototype
21-
* borg
22-
* proxy
23-
* bridge
24-
* graph_search
25-
* state
26-
* builder
27-
* iterator
28-
* strategy
29-
* chain
30-
* mediator
31-
* template
32-
* command
33-
* memento
34-
* visitor
12+
| Pattern | Description |
13+
|:-------:| ----------- |
14+
|[3-tier](3-tier.py)| data<->business logic<->presentation separation (strict relationships) |
15+
|[abstract_factory](abstract_factory.py)| use a generic function with specific factories |
16+
|[adapter](adapter.py)| adapt one interface to another using a whitelist |
17+
|[borg](borg.py)| a singleton with shared-state among instances |
18+
|[bridge](bridge.py)| a client-provider middleman to soften interface changes |
19+
|[builder](builder.py)| call many little discrete methods rather than having a huge number of constructor parameters |
20+
|[catalog](catalog.py)| general methods will call different specialized methods based on construction parameter |
21+
|[chain](chain.py)| apply a chain of successive handlers to try and process the data |
22+
|[command](command.py)| bundle a command and arguments to call later |
23+
|[composite](composite.py)| encapsulate and provide access to a number of different objects |
24+
|[decorator](decorator.py)| wrap functionality with other functionality in order to affect outputs |
25+
|[facade](facade.py)| use one class as an API to a number of others |
26+
|[factory_method](factory_method.py)| delegate a specialized function/method to create instances |
27+
|[flyweight](flyweight.py)| transparently reuse existing instances of objects with similar/identical state |
28+
|[graph_search](graph_search.py)| (graphing algorithms, not design patterns) |
29+
|[mediator](mediator.py)| an object that knows how to connect other objects and act as a proxy |
30+
|[memento](memento.py)| generate an opaque token that can be used to go back to a previous state |
31+
|[mvc](mvc.py)| model<->view<->controller (non-strict relationships) |
32+
|[observer](observer.py)| provide a callback for notification of events/changes to data |
33+
|[pool](pool.py)| preinstantiate and maintain a group of instances of the same type |
34+
|[prototype](prototype.py)| use a factory and clones of a prototype for new instances (if instantiation is expensive) |
35+
|[proxy](proxy.py)| an object funnels operations to something else |
36+
|[publish_subscribe](publish_subscribe.py)| a source syndicates events/data to 0+ registered listeners |
37+
|[state](state.py)| logic is org'd into a discrete number of potential states and the next state that can be transitioned to |
38+
|[strategy](strategy.py)| selectable operations over the same data |
39+
|[template](template.py)| an object imposes a structure but takes pluggable components |
40+
|[visitor](visitor.py)| invoke a callback for all items of a collection |
41+
|[chaining_method](chaining_method.py)| continue callback next object method |

‎__pycache__/facade.cpython-33.pyc‎

-3.51 KB
Binary file not shown.
-6.83 KB
Binary file not shown.

‎__pycache__/null.cpython-33.pyc‎

-2.85 KB
Binary file not shown.

‎abstract_factory.py‎

Lines changed: 27 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,32 +1,34 @@
1+
#!/usr/bin/env python
2+
# -*- coding: utf-8 -*-
3+
14
# http://ginstrom.com/scribbles/2007/10/08/design-patterns-python-style/
25

36
"""Implementation of the abstract factory pattern"""
47

58
importrandom
69

7-
810
classPetShop:
11+
912
"""A pet shop"""
1013

1114
def__init__(self, animal_factory=None):
12-
"""pet_factory is our abstract factory.
13-
We can set it at will."""
15+
"""pet_factory is our abstract factory. We can set it at will."""
1416

1517
self.pet_factory=animal_factory
1618

1719
defshow_pet(self):
18-
"""Creates and shows a pet using the
19-
abstract factory"""
20+
"""Creates and shows a pet using the abstract factory"""
2021

2122
pet=self.pet_factory.get_pet()
22-
print("This is a lovely{}".format(pet))
23+
print("We have a lovely{}".format(pet))
2324
print("It says{}".format(pet.speak()))
24-
print("It eats{}".format(self.pet_factory.get_food()))
25+
print("We also have{}".format(self.pet_factory.get_food()))
2526

2627

2728
# Stuff that our factory makes
2829

2930
classDog:
31+
3032
defspeak(self):
3133
return"woof"
3234

@@ -35,6 +37,7 @@ def __str__(self):
3537

3638

3739
classCat:
40+
3841
defspeak(self):
3942
return"meow"
4043

@@ -45,6 +48,7 @@ def __str__(self):
4548
# Factory classes
4649

4750
classDogFactory:
51+
4852
defget_pet(self):
4953
returnDog()
5054

@@ -53,13 +57,13 @@ def get_food(self):
5357

5458

5559
classCatFactory:
60+
5661
defget_pet(self):
5762
returnCat()
5863

5964
defget_food(self):
6065
return"cat food"
6166

62-
6367
# Create the proper family
6468
defget_factory():
6569
"""Let's be dynamic!"""
@@ -68,8 +72,21 @@ def get_factory():
6872

6973
# Show pets with various factories
7074
if__name__=="__main__":
71-
shop=PetShop()
7275
foriinrange(3):
73-
shop.pet_factory=get_factory()
76+
shop=PetShop(get_factory())
7477
shop.show_pet()
7578
print("="*20)
79+
80+
### OUTPUT ###
81+
# We have a lovely Dog
82+
# It says woof
83+
# We also have dog food
84+
# ====================
85+
# We have a lovely Dog
86+
# It says woof
87+
# We also have dog food
88+
# ====================
89+
# We have a lovely Cat
90+
# It says meow
91+
# We also have cat food
92+
# ====================

‎adapter.py‎

Lines changed: 13 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,41 +1,38 @@
1-
# http://ginstrom.com/scribbles/2008/11/06/generic-adapter-class-in-python/
1+
#!/usr/bin/env python
2+
# -*- coding: utf-8 -*-
23

3-
importos
4+
"""http://ginstrom.com/scribbles/2008/11/06/generic-adapter-class-in-python/"""
45

6+
importos
57

68
classDog(object):
79
def__init__(self):
810
self.name="Dog"
9-
1011
defbark(self):
1112
return"woof!"
1213

13-
1414
classCat(object):
1515
def__init__(self):
1616
self.name="Cat"
17-
1817
defmeow(self):
1918
return"meow!"
2019

21-
2220
classHuman(object):
2321
def__init__(self):
2422
self.name="Human"
25-
2623
defspeak(self):
2724
return"'hello'"
2825

2926

3027
classCar(object):
3128
def__init__(self):
3229
self.name="Car"
33-
3430
defmake_noise(self, octane_level):
3531
return"vroom{0}".format("!"*octane_level)
3632

3733

3834
classAdapter(object):
35+
3936
"""
4037
Adapts an object by replacing methods.
4138
Usage:
@@ -60,6 +57,7 @@ class Adapter(object):
6057
A Human goes 'hello'
6158
A Car goes vroom!!!
6259
"""
60+
6361
def__init__(self, obj, adapted_methods):
6462
"""We set the adapted methods in the object's dict"""
6563
self.obj=obj
@@ -86,5 +84,10 @@ def main():
8684

8785

8886
if__name__=="__main__":
89-
importdoctest
90-
doctest.testmod()
87+
main()
88+
89+
### OUTPUT ###
90+
# A Dog goes woof!
91+
# A Cat goes meow!
92+
# A Human goes 'hello'
93+
# A Car goes vroom!!!

‎append_output.sh‎

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
#!/bin/bash
2+
3+
set -e
4+
5+
src=$(sed -n -e '/### OUTPUT ###/,$!p'"$1")
6+
output=$(python "$1"| sed 's/^/# /')
7+
8+
# These are done separately to avoid having to insert a newline, which causes
9+
# problems when the text itself has '\n' in strings
10+
echo"$src">$1
11+
echo -e "\n### OUTPUT ###">>$1
12+
echo"$output">>$1

‎borg.py‎

Lines changed: 25 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,13 @@
1+
#!/usr/bin/env python
2+
# -*- coding: utf-8 -*-
3+
4+
15
classBorg:
26
__shared_state={}
37

48
def__init__(self):
59
self.__dict__=self.__shared_state
10+
self.state='Init'
611

712
def__str__(self):
813
returnself.state
@@ -18,19 +23,30 @@ class YourBorg(Borg):
1823
rm1.state='Idle'
1924
rm2.state='Running'
2025

21-
print('rm1:', rm1)
22-
print('rm2:', rm2)
26+
print('rm1:{0}'.format(rm1))
27+
print('rm2:{0}'.format(rm2))
2328

2429
rm2.state='Zombie'
2530

26-
print('rm1:', rm1)
27-
print('rm2:', rm2)
31+
print('rm1:{0}'.format(rm1))
32+
print('rm2:{0}'.format(rm2))
2833

29-
print('rm1 id:', id(rm1))
30-
print('rm2 id:', id(rm2))
34+
print('rm1 id:{0}'.format(id(rm1)))
35+
print('rm2 id:{0}'.format(id(rm2)))
3136

3237
rm3=YourBorg()
3338

34-
print('rm1:', rm1)
35-
print('rm2:', rm2)
36-
print('rm3:', rm3)
39+
print('rm1:{0}'.format(rm1))
40+
print('rm2:{0}'.format(rm2))
41+
print('rm3:{0}'.format(rm3))
42+
43+
### OUTPUT ###
44+
# rm1: Running
45+
# rm2: Running
46+
# rm1: Zombie
47+
# rm2: Zombie
48+
# rm1 id: 140732837899224
49+
# rm2 id: 140732837899296
50+
# rm1: Init
51+
# rm2: Init
52+
# rm3: Init

0 commit comments

Comments
(0)