From eff33c5dfd6b5bc14e7be3438fb6a81666102586 Mon Sep 17 00:00:00 2001 From: Peter Gribanov Date: Mon, 4 Sep 2017 19:40:48 +0300 Subject: [PATCH 01/15] correct LSP example --- README.md | 114 +++++++++++++++++++++++++----------------------------- 1 file changed, 52 insertions(+), 62 deletions(-) diff --git a/README.md b/README.md index b5ae5f0..f0136a8 100644 --- a/README.md +++ b/README.md @@ -1149,19 +1149,8 @@ get into trouble. ```php class Rectangle { - protected $width; - protected $height; - - public function __construct() - { - $this->width = 0; - $this->height = 0; - } - - public function render($area) - { - // ... - } + protected $width = 0; + protected $height = 0; public function setWidth($width) { @@ -1173,7 +1162,7 @@ class Rectangle $this->height = $height; } - public function getArea() + public function area() { return $this->width * $this->height; } @@ -1186,50 +1175,42 @@ class Square extends Rectangle $this->width = $this->height = $width; } - public function setHeight(height) + public function setHeight($height) { $this->width = $this->height = $height; } } -function renderLargeRectangles($rectangles) +function rectangleAreaVerifier(Rectangle $rectangle) { - foreach ($rectangles as $rectangle) { - $rectangle->setWidth(4); - $rectangle->setHeight(5); - $area = $rectangle->getArea(); // BAD: Will return 25 for Square. Should be 20. - $rectangle->render($area); - } + $rectangle->setWidth(4); + $rectangle->setHeight(5); + + // BAD: Will return 25 for Square. Should be 20. + return $rectangle->area() == 20; } -$rectangles = [new Rectangle(), new Rectangle(), new Square()]; -renderLargeRectangles($rectangles); +$rectangles = [new Rectangle(), new Square()]; + +foreach ($rectangles as $rectangle) { + if (!rectangleAreaVerifier($rectangle)) { + throw new Exception('Bad area!'); + } +} ``` **Good:** ```php -abstract class Shape +interface Shape { - protected $width; - protected $height; - - abstract public function getArea(); - - public function render($area) - { - // ... - } + public function area(); } -class Rectangle extends Shape +class Rectangle implements Shape { - public function __construct() - { - parent::__construct(); - $this->width = 0; - $this->height = 0; - } + private $width = 0; + private $height = 0; public function setWidth($width) { @@ -1241,48 +1222,57 @@ class Rectangle extends Shape $this->height = $height; } - public function getArea() + public function area() { return $this->width * $this->height; } } -class Square extends Shape +class Square implements Shape { - public function __construct() - { - parent::__construct(); - $this->length = 0; - } + private $length = 0; public function setLength($length) { $this->length = $length; } - public function getArea() + public function area() { return pow($this->length, 2); } } -function renderLargeRectangles($rectangles) +function rectangleAreaVerifier(Rectangle $rectangle) { - foreach ($rectangles as $rectangle) { - if ($rectangle instanceof Square) { - $rectangle->setLength(5); - } elseif ($rectangle instanceof Rectangle) { - $rectangle->setWidth(4); - $rectangle->setHeight(5); - } - - $area = $rectangle->getArea(); - $rectangle->render($area); + $rectangle->setWidth(4); + $rectangle->setHeight(5); + + return $rectangle->area() == 20; +} + +function squareAreaVerifier(Square $square) +{ + $square->setLength(5); + + return $square->area() == 25; +} + +$rectangles = [new Rectangle()]; + +foreach ($rectangles as $rectangle) { + if (!rectangleAreaVerifier($rectangle)) { + throw new Exception('Bad area!'); } } -$shapes = [new Rectangle(), new Rectangle(), new Square()]; -renderLargeRectangles($shapes); +$squares = [new Square()]; + +foreach ($squares as $square) { + if (!squareAreaVerifier($square)) { + throw new Exception('Bad area!'); + } +} ``` **[⬆ back to top](#table-of-contents)** From cb933d10a514ac5ee407b7b40b53bb1c5a36645f Mon Sep 17 00:00:00 2001 From: Peter Gribanov Date: Mon, 4 Sep 2017 20:32:02 +0300 Subject: [PATCH 02/15] rename rectangleAreaVerifier to areaVerifier --- README.md | 20 ++++++++------------ 1 file changed, 8 insertions(+), 12 deletions(-) diff --git a/README.md b/README.md index f0136a8..159c123 100644 --- a/README.md +++ b/README.md @@ -1181,7 +1181,7 @@ class Square extends Rectangle } } -function rectangleAreaVerifier(Rectangle $rectangle) +function areaVerifier(Rectangle $rectangle) { $rectangle->setWidth(4); $rectangle->setHeight(5); @@ -1193,7 +1193,7 @@ function rectangleAreaVerifier(Rectangle $rectangle) $rectangles = [new Rectangle(), new Square()]; foreach ($rectangles as $rectangle) { - if (!rectangleAreaVerifier($rectangle)) { +    if (!areaVerifier($rectangle)) { throw new Exception('Bad area!'); } } @@ -1258,20 +1258,16 @@ function squareAreaVerifier(Square $square) return $square->area() == 25; } -$rectangles = [new Rectangle()]; +$rectangle = new Rectangle(); -foreach ($rectangles as $rectangle) { - if (!rectangleAreaVerifier($rectangle)) { - throw new Exception('Bad area!'); - } +if (!rectangleAreaVerifier($rectangle)) { + throw new Exception('Bad area!'); } -$squares = [new Square()]; +$square = new Square(); -foreach ($squares as $square) { - if (!squareAreaVerifier($square)) { - throw new Exception('Bad area!'); - } +if (!squareAreaVerifier($square)) { + throw new Exception('Bad area!'); } ``` From cb272de8297ea09c4b2102e44cf32b54dc105bec Mon Sep 17 00:00:00 2001 From: Peter Gribanov Date: Mon, 4 Sep 2017 20:42:33 +0300 Subject: [PATCH 03/15] separate client is not good way --- README.md | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 159c123..df832b1 100644 --- a/README.md +++ b/README.md @@ -1199,7 +1199,10 @@ foreach ($rectangles as $rectangle) { } ``` -**Good:** +**Not good:** + +You can separate client for differen shapes. +But this is not a best solution becous the square is still must be a subtype of the rectangle. ```php interface Shape From 263b32be164da73408100d754333074aaac16f5d Mon Sep 17 00:00:00 2001 From: Peter Gribanov Date: Tue, 5 Sep 2017 14:14:42 +0300 Subject: [PATCH 04/15] correct Good solutuin --- README.md | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index df832b1..1d0f44d 100644 --- a/README.md +++ b/README.md @@ -1199,10 +1199,11 @@ foreach ($rectangles as $rectangle) { } ``` -**Not good:** +**Good:** -You can separate client for differen shapes. -But this is not a best solution becous the square is still must be a subtype of the rectangle. +You must separate different shapes. +Despite the apparent similarity of the square and the rectangle, this is not so. +A square also has much in common with a rhombus, but it is not a subtype of a rhombus. ```php interface Shape From 040fd20da89b698aa18d7c5ef04b1fa0a5fbfe15 Mon Sep 17 00:00:00 2001 From: Peter Gribanov Date: Tue, 5 Sep 2017 14:22:20 +0300 Subject: [PATCH 05/15] add immutable example for LSP --- README.md | 54 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 54 insertions(+) diff --git a/README.md b/README.md index 1d0f44d..79dc0a8 100644 --- a/README.md +++ b/README.md @@ -1199,6 +1199,60 @@ foreach ($rectangles as $rectangle) { } ``` +**Not bad:** + +You can solve the problem by making objects immutable, but this is not the best solution. + +```php +class Rectangle +{ + private $width = 0; + private $height = 0; + + public function __construct($width, $height) + { + $this->width = $width; + $this->height = $height; + } + + public function width() + { + return $this->width; + } + + public function height() + { + return $this->height; + } + + public function area() + { + return $this->width * $this->height; + } +} + +class Square extends Rectangle +{ + public function __construct($length) + { + parent::__construct($length, $length); + } +} + +function areaVerifier(Rectangle $rectangle) +{ + return $rectangle->area() == $rectangle->width() * $rectangle->height(); +} + +$rectangles = [new Rectangle(4, 5), new Square(5)]; + +foreach ($rectangles as $rectangle) { + if (!areaVerifier($rectangle)) { + throw new Exception('Bad area!'); + } +} +``` + **Good:** You must separate different shapes. From d868624218da020f2ef7589c6418376fca6c74de Mon Sep 17 00:00:00 2001 From: Peter Gribanov Date: Tue, 5 Sep 2017 17:45:05 +0300 Subject: [PATCH 06/15] remove nonsensical interface Shape --- README.md | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/README.md b/README.md index 79dc0a8..f5f3699 100644 --- a/README.md +++ b/README.md @@ -1260,12 +1260,7 @@ Despite the apparent similarity of the square and the rectangle, this is not so. A square also has much in common with a rhombus, but it is not a subtype of a rhombus. ```php -interface Shape -{ - public function area(); -} - -class Rectangle implements Shape +class Rectangle { private $width = 0; private $height = 0; @@ -1286,7 +1281,7 @@ class Rectangle implements Shape } } -class Square implements Shape +class Square { private $length = 0; From 5c7064a69ca9a4c8d3aa11b1a3a0dcd7c744b59d Mon Sep 17 00:00:00 2001 From: Peter Gribanov Date: Tue, 5 Sep 2017 18:06:42 +0300 Subject: [PATCH 07/15] change example descriptions --- README.md | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index f5f3699..af58d8b 100644 --- a/README.md +++ b/README.md @@ -1201,7 +1201,8 @@ foreach ($rectangles as $rectangle) { **Not bad:** -You can solve the problem by making objects immutable, but this is not the best solution. +You can solve the problem by making objects immutable. +But this is not the best solution, because the square specifies the invariants of the rectangle. ```php class Rectangle @@ -1255,9 +1256,10 @@ foreach ($rectangles as $rectangle) { **Good:** -You must separate different shapes. -Despite the apparent similarity of the square and the rectangle, this is not so. -A square also has much in common with a rhombus, but it is not a subtype of a rhombus. +The best way is separate the quadrangles. +Despite the apparent similarity of the square and the rectangle, they are different. +A square has much in common with a rhombus, and a rectangle with a parallelogram, but they are not subtype. +A square, a rectangle, a rhombus and a parallelogram are separate figures with their own properties, albeit similar. ```php class Rectangle From 2ba99292cd14974f76143908e84e49ed46ef85f5 Mon Sep 17 00:00:00 2001 From: Peter Gribanov Date: Mon, 11 Sep 2017 12:12:14 +0300 Subject: [PATCH 08/15] correct good example --- README.md | 87 ++++++++++++++++++++++++++++++------------------------- 1 file changed, 48 insertions(+), 39 deletions(-) diff --git a/README.md b/README.md index af58d8b..91c801b 100644 --- a/README.md +++ b/README.md @@ -1181,28 +1181,25 @@ class Square extends Rectangle } } -function areaVerifier(Rectangle $rectangle) +function printArea(Rectangle $rectangle) { $rectangle->setWidth(4); $rectangle->setHeight(5); // BAD: Will return 25 for Square. Should be 20. - return $rectangle->area() == 20; + echo sprintf('%s has area %d.', get_class($rectangle), $rectangle->area()).PHP_EOL; } $rectangles = [new Rectangle(), new Square()]; foreach ($rectangles as $rectangle) { -    if (!areaVerifier($rectangle)) { - throw new Exception('Bad area!'); - } + printArea($rectangle); } ``` **Not bad:** You can solve the problem by making objects immutable. -But this is not the best solution, because the square specifies the invariants of the rectangle. ```php class Rectangle @@ -1240,41 +1237,64 @@ class Square extends Rectangle } } -function areaVerifier(Rectangle $rectangle) +function printArea(Rectangle $rectangle) { - return $rectangle->area() == $rectangle->width() * $rectangle->height(); + echo sprintf('%s has area %d.', get_class($rectangle), $rectangle->area()).PHP_EOL; } $rectangles = [new Rectangle(4, 5), new Square(5)]; foreach ($rectangles as $rectangle) { - if (!areaVerifier($rectangle)) { - throw new Exception('Bad area!'); - } + printArea($rectangle); } ``` +This solution no longer violates the LSP principle because we can use a subtype. + +```php +function printSquareArea(Square $rectangle) +{ + // ... +} + +printSquareArea(new Rectangle(4, 5)); +``` + +But this is not a best solution, because the square specifies the invariants of the rectangle. + **Good:** -The best way is separate the quadrangles. +The best way is separate the quadrangles and the allocation of a more general subtype for both shape. + Despite the apparent similarity of the square and the rectangle, they are different. A square has much in common with a rhombus, and a rectangle with a parallelogram, but they are not subtype. A square, a rectangle, a rhombus and a parallelogram are separate figures with their own properties, albeit similar. ```php -class Rectangle +interface Shape +{ + public function area(); +} + +class Rectangle implements Shape { private $width = 0; private $height = 0; - public function setWidth($width) + public function __construct($width, $height) { $this->width = $width; + $this->height = $height; } - public function setHeight($height) + public function width() { - $this->height = $height; + return $this->width; + } + + public function height() + { + return $this->height; } public function area() @@ -1283,46 +1303,35 @@ class Rectangle } } -class Square +class Square implements Shape { private $length = 0; - public function setLength($length) + public function __construct($length) { $this->length = $length; } + public function length() + { + return $this->length; + } + public function area() { return pow($this->length, 2); } } -function rectangleAreaVerifier(Rectangle $rectangle) +function printArea(Shape $shape) { - $rectangle->setWidth(4); - $rectangle->setHeight(5); - - return $rectangle->area() == 20; + echo sprintf('%s has area %d.', get_class($shape), $shape->area()).PHP_EOL; } -function squareAreaVerifier(Square $square) -{ - $square->setLength(5); - - return $square->area() == 25; -} +$shapes = [new Rectangle(4, 5), new Square(5)]; -$rectangle = new Rectangle(); - -if (!rectangleAreaVerifier($rectangle)) { - throw new Exception('Bad area!'); -} - -$square = new Square(); - -if (!squareAreaVerifier($square)) { - throw new Exception('Bad area!'); +foreach ($shapes as $shape) { + printArea($shape); } ``` From e7c25159bd65b3f6fa29b85ef4f41b0a1a65f8bc Mon Sep 17 00:00:00 2001 From: Peter Gribanov Date: Mon, 11 Sep 2017 12:19:56 +0300 Subject: [PATCH 09/15] fix typo --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 91c801b..cc2d024 100644 --- a/README.md +++ b/README.md @@ -1252,7 +1252,7 @@ foreach ($rectangles as $rectangle) { This solution no longer violates the LSP principle because we can use a subtype. ```php -function printSquareArea(Square $rectangle) +function printSquareArea(Square $square) { // ... } @@ -1264,7 +1264,7 @@ But this is not a best solution, because the square specifies the invariants of **Good:** -The best way is separate the quadrangles and the allocation of a more general subtype for both shape. +The best way is separate the quadrangles and allocation of a more general subtype for both shapes. Despite the apparent similarity of the square and the rectangle, they are different. A square has much in common with a rhombus, and a rectangle with a parallelogram, but they are not subtype. From 924c5630041214296cda14abb2c3f7da687e7679 Mon Sep 17 00:00:00 2001 From: Peter Gribanov Date: Tue, 12 Sep 2017 10:11:58 +0300 Subject: [PATCH 10/15] Remove bad eaxample --- README.md | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/README.md b/README.md index c1ec730..1caa41f 100644 --- a/README.md +++ b/README.md @@ -1395,16 +1395,6 @@ foreach ($rectangles as $rectangle) { ``` This solution no longer violates the LSP principle because we can use a subtype. - -```php -function printSquareArea(Square $square) -{ - // ... -} - -printSquareArea(new Rectangle(4, 5)); -``` - But this is not a best solution, because the square specifies the invariants of the rectangle. **Good:** From ab07e05bcd144229790da8d4ba4466e44db6826c Mon Sep 17 00:00:00 2001 From: Peter Gribanov Date: Tue, 12 Sep 2017 10:18:00 +0300 Subject: [PATCH 11/15] use PHP 5.6 pow() --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 1caa41f..3cc4698 100644 --- a/README.md +++ b/README.md @@ -1454,8 +1454,8 @@ class Square implements Shape public function area() { - return pow($this->length, 2); - } +        return $this->length ** 2; +    } } function printArea(Shape $shape) From c2af508723f7bc2b56596609016897b2cecec3a6 Mon Sep 17 00:00:00 2001 From: Peter Gribanov Date: Tue, 12 Sep 2017 18:34:24 +0300 Subject: [PATCH 12/15] fix typo --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 3cc4698..47c3c60 100644 --- a/README.md +++ b/README.md @@ -1403,7 +1403,7 @@ The best way is separate the quadrangles and allocation of a more general subtyp Despite the apparent similarity of the square and the rectangle, they are different. A square has much in common with a rhombus, and a rectangle with a parallelogram, but they are not subtype. -A square, a rectangle, a rhombus and a parallelogram are separate figures with their own properties, albeit similar. +A square, a rectangle, a rhombus and a parallelogram are separate shapes with their own properties, albeit similar. ```php interface Shape From 1456a97ddf35ae955ee88b2f006a42ff45a645ac Mon Sep 17 00:00:00 2001 From: Peter Gribanov Date: Mon, 27 Nov 2017 11:03:45 +0300 Subject: [PATCH 13/15] add prifix for getters --- README.md | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/README.md b/README.md index eaa8ab5..1e16064 100644 --- a/README.md +++ b/README.md @@ -1647,7 +1647,7 @@ class Rectangle $this->height = $height; } - public function area(): int + public function getArea(): int { return $this->width * $this->height; } @@ -1672,7 +1672,7 @@ function printArea(Rectangle $rectangle): void $rectangle->setHeight(5); // BAD: Will return 25 for Square. Should be 20. - echo sprintf('%s has area %d.', get_class($rectangle), $rectangle->area()).PHP_EOL; + echo sprintf('%s has area %d.', get_class($rectangle), $rectangle->getArea()).PHP_EOL; } $rectangles = [new Rectangle(), new Square()]; @@ -1698,17 +1698,17 @@ class Rectangle $this->height = $height; } - public function width(): int + public function getWidth(): int { return $this->width; } - public function height(): int + public function getHeight(): int { return $this->height; } - public function area(): int + public function getArea(): int { return $this->width * $this->height; } @@ -1724,7 +1724,7 @@ class Square extends Rectangle function printArea(Rectangle $rectangle): void { - echo sprintf('%s has area %d.', get_class($rectangle), $rectangle->area()).PHP_EOL; + echo sprintf('%s has area %d.', get_class($rectangle), $rectangle->getArea()).PHP_EOL; } $rectangles = [new Rectangle(4, 5), new Square(5)]; @@ -1748,7 +1748,7 @@ A square, a rectangle, a rhombus and a parallelogram are separate shapes with th ```php interface Shape { - public function area(): int; + public function getArea(): int; } class Rectangle implements Shape @@ -1762,17 +1762,17 @@ class Rectangle implements Shape $this->height = $height; } - public function width(): int + public function getWdth(): int { return $this->width; } - public function height(): int + public function getHeight(): int { return $this->height; } - public function area(): int + public function getArea(): int { return $this->width * $this->height; } @@ -1787,12 +1787,12 @@ class Square implements Shape $this->length = $length; } - public function length(): int + public function getLength(): int { return $this->length; } - public function area(): int + public function getArea(): int {        return $this->length ** 2;    } @@ -1800,7 +1800,7 @@ class Square implements Shape function printArea(Shape $shape): void { - echo sprintf('%s has area %d.', get_class($shape), $shape->area()).PHP_EOL; + echo sprintf('%s has area %d.', get_class($shape), $shape->getArea()).PHP_EOL; } $shapes = [new Rectangle(4, 5), new Square(5)]; From 68a00031cd9cef334a5a362828435a675d3aa33d Mon Sep 17 00:00:00 2001 From: Peter Gribanov Date: Mon, 27 Nov 2017 15:58:10 +0300 Subject: [PATCH 14/15] remove Not bad section --- README.md | 55 ------------------------------------------------------- 1 file changed, 55 deletions(-) diff --git a/README.md b/README.md index 1e16064..bc7e307 100644 --- a/README.md +++ b/README.md @@ -1682,61 +1682,6 @@ foreach ($rectangles as $rectangle) { } ``` -**Not bad:** - -You can solve the problem by making objects immutable. - -```php -class Rectangle -{ - private $width = 0; - private $height = 0; - - public function __construct(int $width, int $height) - { - $this->width = $width; - $this->height = $height; - } - - public function getWidth(): int - { - return $this->width; - } - - public function getHeight(): int - { - return $this->height; - } - - public function getArea(): int - { - return $this->width * $this->height; - } -} - -class Square extends Rectangle -{ - public function __construct(int $length) - { - parent::__construct($length, $length); - } -} - -function printArea(Rectangle $rectangle): void -{ - echo sprintf('%s has area %d.', get_class($rectangle), $rectangle->getArea()).PHP_EOL; -} - -$rectangles = [new Rectangle(4, 5), new Square(5)]; - -foreach ($rectangles as $rectangle) { - printArea($rectangle); -} -``` - -This solution no longer violates the LSP principle because we can use a subtype. -But this is not a best solution, because the square specifies the invariants of the rectangle. - **Good:** The best way is separate the quadrangles and allocation of a more general subtype for both shapes. From 6c1da67e2816b28c25346d5e355a1d8c889fa719 Mon Sep 17 00:00:00 2001 From: Peter Gribanov Date: Tue, 27 Feb 2018 00:05:40 +0300 Subject: [PATCH 15/15] remove not used getters --- README.md | 15 --------------- 1 file changed, 15 deletions(-) diff --git a/README.md b/README.md index e8156bd..f1f5b6c 100644 --- a/README.md +++ b/README.md @@ -1747,16 +1747,6 @@ class Rectangle implements Shape $this->height = $height; } - public function getWdth(): int - { - return $this->width; - } - - public function getHeight(): int - { - return $this->height; - } - public function getArea(): int { return $this->width * $this->height; @@ -1772,11 +1762,6 @@ class Square implements Shape $this->length = $length; } - public function getLength(): int - { - return $this->length; - } - public function getArea(): int {        return $this->length ** 2;