Skip to content

Commit 480905b

Browse files
committed
Merge branch 'washwash-master'
2 parents 07fe6ec + dd5d67a commit 480905b

File tree

5 files changed

+195
-3
lines changed

5 files changed

+195
-3
lines changed

3-tier.py

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,12 +12,11 @@ class Data(object):
1212
}
1313

1414
def __get__(self, obj, klas):
15-
print ("(Fetching from Data Store)")
15+
print("(Fetching from Data Store)")
1616
return {'products': self.products}
1717

1818

1919
class BusinessLogic(object):
20-
2120
""" Business logic holding data store instances """
2221

2322
data = Data()

README.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ Current Patterns:
2525
| [decorator](decorator.py) | wrap functionality with other functionality in order to affect outputs |
2626
| [facade](facade.py) | use one class as an API to a number of others |
2727
| [factory_method](factory_method.py) | delegate a specialized function/method to create instances |
28+
| [front_controller](front_controller.py) | single handler requests coming to the application |
2829
| [flyweight](flyweight.py) | transparently reuse existing instances of objects with similar/identical state |
2930
| [graph_search](graph_search.py) | (graphing algorithms, not design patterns) |
3031
| [lazy_evaluation](lazy_evaluation.py) | lazily-evaluated property pattern in Python |
@@ -36,6 +37,7 @@ Current Patterns:
3637
| [prototype](prototype.py) | use a factory and clones of a prototype for new instances (if instantiation is expensive) |
3738
| [proxy](proxy.py) | an object funnels operations to something else |
3839
| [publish_subscribe](publish_subscribe.py) | a source syndicates events/data to 0+ registered listeners |
40+
| [specification](specification.py) | business rules can be recombined by chaining the business rules together using boolean logic |
3941
| [state](state.py) | logic is org'd into a discrete number of potential states and the next state that can be transitioned to |
4042
| [strategy](strategy.py) | selectable operations over the same data |
4143
| [template](template.py) | an object imposes a structure but takes pluggable components |

adapter.py

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,6 @@ def make_noise(self, octane_level):
3737

3838

3939
class Adapter(object):
40-
4140
"""
4241
Adapts an object by replacing methods.
4342
Usage:

front_controller.py

Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
#!/usr/bin/env python
2+
# -*- coding: utf-8 -*-
3+
4+
"""
5+
@author: Gordeev Andrey <gordeev.and.and@gmail.com>
6+
The controller provides a centralized entry point that controls and manages
7+
request handling.
8+
"""
9+
10+
11+
class MobileView(object):
12+
def show_index_page(self):
13+
print('Displaying mobile index page')
14+
15+
16+
class TabletView(object):
17+
def show_index_page(self):
18+
print('Displaying tablet index page')
19+
20+
21+
class Dispatcher(object):
22+
def __init__(self):
23+
self.mobile_view = MobileView()
24+
self.tablet_view = TabletView()
25+
26+
def dispatch(self, request):
27+
if request.type == Request.mobile_type:
28+
self.mobile_view.show_index_page()
29+
elif request.type == Request.tablet_type:
30+
self.tablet_view.show_index_page()
31+
else:
32+
print('cant dispatch the request')
33+
34+
35+
class RequestController(object):
36+
""" front controller """
37+
def __init__(self):
38+
self.dispatcher = Dispatcher()
39+
40+
def dispatch_request(self, request):
41+
if isinstance(request, Request):
42+
self.dispatcher.dispatch(request)
43+
else:
44+
print('request must be a Request object')
45+
46+
47+
class Request(object):
48+
""" request """
49+
50+
mobile_type = 'mobile'
51+
tablet_type = 'tablet'
52+
53+
def __init__(self, request):
54+
self.type = None
55+
request = request.lower()
56+
if request == self.mobile_type:
57+
self.type = self.mobile_type
58+
elif request == self.tablet_type:
59+
self.type = self.tablet_type
60+
61+
62+
if __name__ == '__main__':
63+
front_controller = RequestController()
64+
front_controller.dispatch_request(Request('mobile'))
65+
front_controller.dispatch_request(Request('tablet'))
66+
67+
front_controller.dispatch_request(Request('desktop'))
68+
front_controller.dispatch_request('mobile')
69+
70+
71+
### OUTPUT ###
72+
# Displaying mobile index page
73+
# Displaying tablet index page
74+
# cant dispatch the request
75+
# request must be a Request object

specification.py

Lines changed: 117 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,117 @@
1+
#!/usr/bin/env python
2+
# -*- coding: utf-8 -*-
3+
4+
"""
5+
@author: Gordeev Andrey <gordeev.and.and@gmail.com>
6+
7+
Specification provide recombination business logic by
8+
chaining together using boolean logic
9+
"""
10+
11+
from abc import abstractmethod
12+
13+
14+
class Specification(object):
15+
16+
def and_specification(self, candidate):
17+
raise NotImplementedError()
18+
19+
def or_specification(self, candidate):
20+
raise NotImplementedError()
21+
22+
def not_specification(self):
23+
raise NotImplementedError()
24+
25+
@abstractmethod
26+
def is_satisfied_by(self, candidate):
27+
pass
28+
29+
30+
class CompositeSpecification(Specification):
31+
@abstractmethod
32+
def is_satisfied_by(self, candidate):
33+
pass
34+
35+
def and_specification(self, candidate):
36+
return AndSpecification(self, candidate)
37+
38+
def or_specification(self, candidate):
39+
return OrSpecification(self, candidate)
40+
41+
def not_specification(self):
42+
return NotSpecification(self)
43+
44+
45+
class AndSpecification(CompositeSpecification):
46+
_one = Specification()
47+
_other = Specification()
48+
49+
def __init__(self, one, other):
50+
self._one = one
51+
self._other = other
52+
53+
def is_satisfied_by(self, candidate):
54+
return bool(self._one.is_satisfied_by(candidate) and
55+
self._other.is_satisfied_by(candidate))
56+
57+
58+
class OrSpecification(CompositeSpecification):
59+
_one = Specification()
60+
_other = Specification()
61+
62+
def __init__(self, one, other):
63+
self._one = one
64+
self._other = other
65+
66+
def is_satisfied_by(self, candidate):
67+
return bool(self._one.is_satisfied_by(candidate) or
68+
self._other.is_satisfied_by(candidate))
69+
70+
71+
class NotSpecification(CompositeSpecification):
72+
_wrapped = Specification()
73+
74+
def __init__(self, wrapped):
75+
self._wrapped = wrapped
76+
77+
def is_satisfied_by(self, candidate):
78+
return bool(not self._wrapped.is_satisfied_by(candidate))
79+
80+
81+
class User(object):
82+
83+
def __init__(self, super_user=False):
84+
self.super_user = super_user
85+
86+
87+
class UserSpecification(CompositeSpecification):
88+
89+
def is_satisfied_by(self, candidate):
90+
return isinstance(candidate, User)
91+
92+
93+
class SuperUserSpecification(CompositeSpecification):
94+
95+
def is_satisfied_by(self, candidate):
96+
return getattr(candidate, 'super_user', False)
97+
98+
99+
if __name__ == '__main__':
100+
print('Specification')
101+
andrey = User()
102+
ivan = User(super_user=True)
103+
vasiliy = 'not User instance'
104+
105+
root_specification = UserSpecification().\
106+
and_specification(SuperUserSpecification())
107+
108+
print(root_specification.is_satisfied_by(andrey))
109+
print(root_specification.is_satisfied_by(ivan))
110+
print(root_specification.is_satisfied_by(vasiliy))
111+
112+
113+
### OUTPUT ###
114+
# Specification
115+
# False
116+
# True
117+
# False

0 commit comments

Comments
 (0)