![](/assets/images/project_default_logo.png)
![](/assets/images/default-avatar-128.png)
Add code for Liskov Substitution Principle.
@80812924a4279a82b0441b81f45d910a4bad9903
--- README.md
+++ README.md
... | ... | @@ -10,7 +10,10 @@ |
10 | 10 |
- [link](http://joelabrahamsson.com/a-simple-example-of-the-openclosed-principle/) |
11 | 11 |
- `L`: Liskov Substitution Principle. |
12 | 12 |
- [link](http://www.objectmentor.com/resources/articles/lsp.pdf) |
13 |
+ - [Stack Overflow](http://stackoverflow.com/questions/56860/what-is-the-liskov-substitution-principle) |
|
13 | 14 |
- [Circle-Ellipse Problem](https://en.wikipedia.org/wiki/Circle-ellipse_problem) |
15 |
+ - **Moral of the story: model your classes based on behaviours not on properties; model your data based on properties and not on behaviours. If it behaves like a duck, it's certainly a bird.** |
|
16 |
+ - **This strongly suggests that inheritance should never be used when the sub-class restricts the freedom implicit in the base class, but should only be used when the sub-class adds extra detail to the concept represented by the base class as in 'Monkey' is-an 'Animal'.** |
|
14 | 17 |
- `I`: |
15 | 18 |
- `D`: |
16 | 19 |
|
... | ... | @@ -18,3 +21,4 @@ |
18 | 21 |
|
19 | 22 |
- [Programming Done By Superstition](https://utcc.utoronto.ca/~cks/space/blog/programming/ProgrammingViaSuperstition) |
20 | 23 |
- [Object Mentor](http://www.objectmentor.com/resources/publishedArticles.html) |
24 |
+- [Clean Coder](http://cleancoders.com/category/fundamentals) |
+++ python_code/bad/ISP.py
... | ... | @@ -0,0 +1,0 @@ |
+++ python_code/bad/LSP.py
... | ... | @@ -0,0 +1,48 @@ |
1 | +#!/usr/bin/env python | |
2 | +# -*- coding: utf-8 -*- | |
3 | +# The violation of LSP here is that a `Prisoner` is not a suitable | |
4 | +# substitution of `Person` since they "behave" differently. | |
5 | +# Remember, the principle is that you should model your class according | |
6 | +# to their behavior rather than porperties. See "Circle-Ecllipse Problem" | |
7 | +# for detail. | |
8 | +import copy | |
9 | + | |
10 | +class Person(object): | |
11 | + | |
12 | + def __init__(self, position): | |
13 | + self.position = position | |
14 | + | |
15 | + def walk_North(self, dist): | |
16 | + self.position[1] += dist | |
17 | + | |
18 | + def walk_East(self, dist): | |
19 | + self.position[0] += dist | |
20 | + | |
21 | +# `Prisoner` is a logicall natural extension of `Person` | |
22 | +# since they fulfill the "is-a" relation: a `Prisoner` is a `Person`. | |
23 | +# However, such extension violate LSP in this case. | |
24 | +class Prisoner(Person): | |
25 | + PRISON_LOCATION = [3, 3] | |
26 | + | |
27 | + def __init__(self): | |
28 | + super(Prisoner, self).__init__(copy.copy(self.PRISON_LOCATION)) | |
29 | + self.is_free = False | |
30 | + | |
31 | +# The issue here is that `Prisoner` inherite `walk_North` and `walk_East` methods | |
32 | +# from the `Person` which is not logically correct for the `Prisoner` class. | |
33 | + | |
34 | +def main(): | |
35 | + prisoner = Prisoner() | |
36 | + print "The prisoner trying to walk to north by 10 and east by -3." | |
37 | + | |
38 | + try: | |
39 | + prisoner.walk_North(10) | |
40 | + prisoner.walk_East(-3) | |
41 | + except: | |
42 | + pass | |
43 | + | |
44 | + print "The location of the prison: {}".format(prisoner.PRISON_LOCATION) | |
45 | + print "The current position of the prisoner: {}".format(prisoner.position) | |
46 | + | |
47 | +if __name__ == "__main__": | |
48 | + main()(파일 끝에 줄바꿈 문자 없음) |
+++ python_code/good/ISP.py
... | ... | @@ -0,0 +1,0 @@ |
+++ python_code/good/LSP.py
... | ... | @@ -0,0 +1,42 @@ |
1 | +#!/usr/bin/env python | |
2 | +# -*- coding: utf-8 -*- | |
3 | +# As we can see in `python_code.bad.LSP` module where a violation | |
4 | +# of LSP may lead to an unexpected behaviour of sub-types. In our | |
5 | +# example, "is-a" relation can not directly applied to `Person` and | |
6 | +# `Prisoner`. The cause is that these two classes "behave" differently. | |
7 | +# How to fix it? Maybe a better naming will do the trick: | |
8 | + | |
9 | +class FreeMan(object): | |
10 | + | |
11 | + def __init__(self, position): | |
12 | + self.position = position | |
13 | + | |
14 | + def walk_North(self, dist): | |
15 | + self.position[1] += dist | |
16 | + | |
17 | + def walk_East(self, dist): | |
18 | + self.position[0] += dist | |
19 | + | |
20 | +# "is-a" relationship no longer holds since a `Prisoner` is not a `FreeMan`. | |
21 | +class Prisoner(object): | |
22 | + PRISON_LOCATION = (3, 3) | |
23 | + | |
24 | + def __init__(self): | |
25 | + self.position = type(self).PRISON_LOCATION | |
26 | + | |
27 | +def main(): | |
28 | + | |
29 | + prisoner = Prisoner() | |
30 | + print "The prisoner trying to walk to north by 10 and east by -3." | |
31 | + | |
32 | + try: | |
33 | + prisoner.walk_North(10) | |
34 | + prisoner.walk_East(-3) | |
35 | + except: | |
36 | + pass | |
37 | + | |
38 | + print "The location of the prison: {}".format(prisoner.PRISON_LOCATION) | |
39 | + print "The current position of the prisoner: {}".format(prisoner.position) | |
40 | + | |
41 | +if __name__ == "__main__": | |
42 | + 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?