![](/assets/images/project_default_logo.png)
![](/assets/images/default-avatar-128.png)
Initial commit. Add example code for open/close principle.
@9a828ee80bb00ecb05f13f4fda67c0d29b5948a1
+++ python_code/__init__.py
... | ... | @@ -0,0 +1,0 @@ |
+++ python_code/__init__.pyc
Binary file is not shown |
+++ python_code/bad/__init__.py
... | ... | @@ -0,0 +1,0 @@ |
+++ python_code/bad/__init__.pyc
Binary file is not shown |
+++ python_code/bad/open_close.py
... | ... | @@ -0,0 +1,36 @@ |
1 | +#!/usr/bin/env python | |
2 | +# -*- coding: utf-8 -*- | |
3 | + | |
4 | +# Think about what will happen if you want to extend the class to calculate | |
5 | +# the area of different shape? What would you do with the code in the property | |
6 | +# `total_area` of class `AreaCalculator`? | |
7 | + | |
8 | +class Rectangle(object): | |
9 | + | |
10 | + def __init__(self, width, height): | |
11 | + self.width = width | |
12 | + self.height = height | |
13 | + | |
14 | +class AreaCalculator(object): | |
15 | + | |
16 | + def __init__(self, shapes): | |
17 | + | |
18 | + assert isinstance(shapes, list), "`shapes` should be of type `list`." | |
19 | + self.shapes = shapes | |
20 | + | |
21 | + @property | |
22 | + def total_area(self): | |
23 | + total = 0 | |
24 | + for shape in self.shapes: | |
25 | + total += shape.width * shape.height | |
26 | + | |
27 | + return total | |
28 | + | |
29 | +def main(): | |
30 | + shapes = [Rectangle(2, 3), Rectangle(1, 6)] | |
31 | + calculator = AreaCalculator(shapes) | |
32 | + print "The total area is: ", calculator.total_area | |
33 | + | |
34 | +if __name__ == '__main__': | |
35 | + | |
36 | + main() |
+++ python_code/good/__init__.py
... | ... | @@ -0,0 +1,0 @@ |
+++ python_code/good/__init__.pyc
Binary file is not shown |
+++ python_code/good/open_close.py
... | ... | @@ -0,0 +1,50 @@ |
1 | +#!/usr/bin/env python | |
2 | +# -*- coding: utf-8 -*- | |
3 | +# This is a reimplementation of `python_code.bad.open_close` module which | |
4 | +# abides by the open/close principle. You can see that it will be easy to | |
5 | +# extend the functionality of `AreaCalculator` in this module whereas it | |
6 | +# is not in `python_code.bad.open_close` module. | |
7 | + | |
8 | +from abc import ABCMeta, abstractproperty | |
9 | + | |
10 | +class Shape(object): | |
11 | + __metaclass__ = ABCMeta | |
12 | + | |
13 | + @abstractproperty | |
14 | + def area(self): | |
15 | + pass | |
16 | + | |
17 | +class Rectangle(Shape): | |
18 | + | |
19 | + def __init__(self, width, height): | |
20 | + self.width = width | |
21 | + self.height = height | |
22 | + | |
23 | + @property | |
24 | + def area(self): | |
25 | + return self.width * self.height | |
26 | + | |
27 | +class AreaCalculator(object): | |
28 | + | |
29 | + def __init__(self, shapes): | |
30 | + self.shapes = shapes | |
31 | + | |
32 | + @property | |
33 | + def total_area(self): | |
34 | + total = 0 | |
35 | + for shape in self.shapes: | |
36 | + total += shape.area | |
37 | + return total | |
38 | + | |
39 | +# Note that if we want to extend the functionality of AreaCalculator to support calculating | |
40 | +# area of different shape, we only need to define new subtype of `Shape` and leave other code | |
41 | +# alone without modify them. That is the key of open/close principle. | |
42 | + | |
43 | +def main(): | |
44 | + shapes = [Rectangle(1, 6), Rectangle(2, 3)] | |
45 | + calculator = AreaCalculator(shapes) | |
46 | + | |
47 | + print "The total area is: ", calculator.total_area | |
48 | + | |
49 | +if __name__ == '__main__': | |
50 | + main() |
Add a comment
Delete comment
Once you delete this comment, you won't be able to recover it. Are you sure you want to delete this comment?