SOLID: Първите 5 принципа на обектно ориентиран софтуерен дизайн, част: 2 Принцип отворено-затворен

Част 2 – SOLID: Първите 5 принципа на обектно ориентиран софтуерен дизайн, част: 2 Принцип отворено-затворен
Отворено-затвореният принцип (OCP) гласи:
Обектите трябва да са отворени за разширение, но затворени за модификация за други програмисти.
Това означава, че един клас трябва да бъде разширяем, без да се модифицира самият клас .
Нека да разгледаме отново AreaCalculator класа и да се съсредоточим върху sum метода:
class AreaCalculator
{
protected $shapes;
public function __construct($shapes = [])
{
$this->shapes = $shapes;
}
public function sum()
{
foreach ($this->shapes as $shape) {
if (is_a($shape, 'Square')) {
$area[] = pow($shape->length, 2);
} elseif (is_a($shape, 'Circle')) {
$area[] = pi() * pow($shape->radius, 2);
}
}
return array_sum($area);
}
}Помислете за сценарий, при който потребителят би искал метода sum да има допълнителни форми като триъгълници, петоъгълници, шестоъгълници и т.н. Ще трябва постоянно да редактирате този файл и да добавяте още if/ else блокове. Това би нарушило принципа отворено-затворено.
Начинът, по който можете да направите този sum метод по-добър, е да премахнете логиката за изчисляване на площта на всяка форма от AreaCalculator метода на класа и да я прикрепите към класа на всяка форма.
Ето area метода, дефиниран в Square:
class Square
{
public $length;
public function __construct($length)
{
$this->length = $length;
}
public function area()
{
return pow($this->length, 2);
}
}И ето area метода, дефиниран в Circle:
class Circle
{
public $radius;
public function construct($radius)
{
$this->radius = $radius;
}
public function area()
{
return pi() * pow($shape->radius, 2);
}
}След това sum методът за AreaCalculator може да бъде пренаписан като:
class AreaCalculator
{
// ...
public function sum()
{
foreach ($this->shapes as $shape) {
$area[] = $shape->area();
}
return array_sum($area);
}
}Сега можете да създадете друг клас на форма и да го предадете, когато изчислявате сумата, без да нарушавате кода.
Възниква обаче друг проблем. Как да разберете, че обектът, прехвърлен в, AreaCalculator всъщност е форма или ако формата има метод с име area?
Кодирането на интерфейс е неразделна част от SOLID.
Създайте файл, ShapeInterfaceкойто поддържа area:
interface ShapeInterface
{
public function area();
}Промяна на формата ви класове implement на ShapeInterface.
Ето актуализацията за Square:
class Square implements ShapeInterface
{
// ...
}А ето и актуализацията за Circle:
class Circle implements ShapeInterface
{
// ...
}В sum метода за AreaCalculator, можете да проверите дали предоставените форми същност са екземпляри на ShapeInterface; в противен случай покажете изключение( throw ):
class AreaCalculator
{
// ...
public function sum()
{
foreach ($this->shapes as $shape) {
if (is_a($shape, 'ShapeInterface')) {
$area[] = $shape->area();
continue;
}
throw new AreaCalculatorInvalidShapeException();
}
return array_sum($area);
}
}Това отговаря на принципа отворено-затворено в SOLID


