Zasada otwarte/zamknięte

"Dochodzenie do mistrzostwa wymaga dwóch elementów: wiedzy i pracy." - Robert C. Martin

Zasada otwarte/zamknięte

Zasada otwarte/zamknięte

Według zasady otwarte/zamknięte każda klasa powinna być otwarta na rozbudowę, ale zamknięta na modyfikacje. Klasy powinny być pisane tak, aby na każdym etapie rozwoju aplikacji istniała możliwość ich rozszerzenia. Rozszerzenie takiej klasy powinno być przeprowadzone bez konieczności wprowadzania modyfikacji już w istniejącej części kodu. Czyli do klasy możemy dodawać nowe funkcje i rozszerzenia klasy, ale bez zmiany jej wewnętrznego działania. Wszelkie zmiany w kodzie są niepożądane, gdyż często zmiana deklaracji metody powoduje awarię programu w innym miejscu. Zasada ta jest szczególnie ważna w przypadku dużych projektów, nad którymi pracuje wielu programistów. Stosowanie zasady otwarte/zamknięte sprowadza się do świadomego użycia kompozycji, dziedziczenia czy modyfikatorów dostępu. Przedstawiony poniżej kod źródłowy w języku PHP łamie zasadę OCP. Dodanie nowego gatunku spowoduje konieczność modyfikacji istniejącej już klasy AnimalMotion, odpowiedzialnej za ruch. W takim wypadku trzeba będzie dodać kolejny warunek, który w zależności od dodanego gatunku wykona odpowiedni dla niego ruch.

class Pigeon 
{ 
private $flyingSpeed; 

public function __construct($flyingSpeed) 
{ 
$this->flyingSpeed = $flyingSpeed;
}
}

class Cheetah
{
private $runningSpeed;

public function __construct($runningSpeed)
{
$this->runningSpeed = $runningSpeed;
}
}

class AnimalMotion
{
public funtion move($animal)
{
if(is_a($animal,'Pigeon')) echo 'Lecę!';
else if(is_a($animal,'Chetaah')) echo 'Biegnę!';
}
}

$animal = new Chetaah('50');
$move = new AnimalMotion();
$move->move($animal);

W takiej sytuacji najlepiej posłużyć się polimorfizmem, gdyż dzięki niemu można obarczyć koniecznością implementacji metody wywołującej ruch zwierzęcia każdą klasę reprezentującą dany gatunek. W poniższym przykładzie została zastosowana zasada OCP, poprzez zastosowanie klasy abstrakcyjnej Animal. Do funkcji implementowanej w klasie AnimalMotion przekazywany jest jako argument cały obiekt $animal, który został utworzony w obrębie klasy danego gatunku. Dzięki temu zachowana jest również zasada SRP, gdyż za ruch zwierzęcia jest odpowiedzialna tylko klasa AnimalMotion. Klasy odpowiedzialne za utworzenie zwierzęcia danego gatunku np. Cheetah czy Pigeon zawierają jedynie implementację metody move().

abstract class Animal 
{ 
public abstract function move(); 
} 

class Pigeon extends Animal 
{ 
private $flyingSpeed; 

public function __construct($flyingSpeed) 
{ 
$this->flyingSpeed = $flyingSpeed;
}

public funtion move()
{
echo 'Lecę!';
}
}

class Cheetah extends Animal
{
private $runningSpeed;

public function __construct($runningSpeed)
{
$this->runningSpeed = $runningSpeed;
}

public funtion move()
{
echo 'Biegnę!';
}
}

class AnimalMotion
{
public funtion move(Animal $animal)
{
return $animal->move();
}
}

$animal = new Chetaah('50');
$move = new AnimalMotion();
$move->move($animal);
?>