@@ -861,6 +861,144 @@ class AjaxRequester {
861
861
```
862
862
** [ ⬆ back to top] ( #table-of-contents ) **
863
863
864
+
865
+ ### Liskov Substitution Principle (LSP)
866
+ This is a scary term for a very simple concept. It's formally defined as "If S
867
+ is a subtype of T, then objects of type T may be replaced with objects of type S
868
+ (i.e., objects of type S may substitute objects of type T) without altering any
869
+ of the desirable properties of that program (correctness, task performed,
870
+ etc.)." That's an even scarier definition.
871
+
872
+ The best explanation for this is if you have a parent class and a child class,
873
+ then the base class and child class can be used interchangeably without getting
874
+ incorrect results. This might still be confusing, so let's take a look at the
875
+ classic Square-Rectangle example. Mathematically, a square is a rectangle, but
876
+ if you model it using the "is-a" relationship via inheritance, you quickly
877
+ get into trouble.
878
+
879
+ ** Bad:**
880
+ ``` javascript
881
+ class Rectangle {
882
+ constructor () {
883
+ this .width = 0 ;
884
+ this .height = 0 ;
885
+ }
886
+
887
+ setColor (color ) {
888
+ // ...
889
+ }
890
+
891
+ render (area ) {
892
+ // ...
893
+ }
894
+
895
+ setWidth (width ) {
896
+ this .width = width;
897
+ }
898
+
899
+ setHeight (height ) {
900
+ this .height = height;
901
+ }
902
+
903
+ getArea () {
904
+ return this .width * this .height ;
905
+ }
906
+ }
907
+
908
+ class Square extends Rectangle {
909
+ constructor () {
910
+ super ();
911
+ }
912
+
913
+ setWidth (width ) {
914
+ this .width = width;
915
+ this .height = width;
916
+ }
917
+
918
+ setHeight (height ) {
919
+ this .width = height;
920
+ this .height = height;
921
+ }
922
+ }
923
+
924
+ function renderLargeRectangles (rectangles ) {
925
+ rectangles .forEach ((rectangle ) => {
926
+ rectangle .setWidth (4 );
927
+ rectangle .setHeight (5 );
928
+ let area = rectangle .getArea (); // BAD: Will return 25 for Square. Should be 20.
929
+ rectangle .render (area);
930
+ })
931
+ }
932
+
933
+ let rectangles = [new Rectangle (), new Rectangle (), new Square ()];
934
+ renderLargeRectangles (rectangles);
935
+ ```
936
+
937
+ ** Good** :
938
+ ``` javascript
939
+ class Shape {
940
+ constructor () {}
941
+
942
+ setColor (color ) {
943
+ // ...
944
+ }
945
+
946
+ render (area ) {
947
+ // ...
948
+ }
949
+ }
950
+
951
+ class Rectangle extends Shape {
952
+ constructor () {
953
+ super ();
954
+ this .width = 0 ;
955
+ this .height = 0 ;
956
+ }
957
+
958
+ setWidth (width ) {
959
+ this .width = width;
960
+ }
961
+
962
+ setHeight (height ) {
963
+ this .height = height;
964
+ }
965
+
966
+ getArea () {
967
+ return this .width * this .height ;
968
+ }
969
+ }
970
+
971
+ class Square extends Shape {
972
+ constructor () {
973
+ super ();
974
+ this .length = 0 ;
975
+ }
976
+
977
+ setLength (length ) {
978
+ this .length = length;
979
+ }
980
+ }
981
+
982
+ function renderLargeShapes (shapes ) {
983
+ shapes .forEach ((shape ) => {
984
+ switch (shape .constructor .name ) {
985
+ case ' Square' :
986
+ shape .setLength (5 );
987
+ case ' Rectangle' :
988
+ shape .setWidth (4 );
989
+ shape .setHeight (5 );
990
+ }
991
+
992
+ let area = shape .getArea ();
993
+ shape .render (area);
994
+ })
995
+ }
996
+
997
+ let shapes = [new Rectangle (), new Rectangle (), new Square ()];
998
+ renderLargeShapes ();
999
+ ```
1000
+ ** [ ⬆ back to top] ( #table-of-contents ) **
1001
+
864
1002
### Prefer ES6 classes over ES5 plain functions
865
1003
It's very difficult to get readable class inheritance, construction, and method
866
1004
definitions for classical ES5 classes. If you need inheritance (and be aware
0 commit comments