Open/Closed Principle

"There are two parts to learning craftsmanship: knowledge and work." - Robert C. Martin

Open/Closed Principle

Zasada otwarte/zamknięte

According to the open/closed principle, each class should be open to development, but closed to modifications. Classes should be written in such way that at each stage of application development there is possibility of extending them. The extension of such class should be carried out without the need to modify it in existing part of code.

That is, we can add new functions and class extensions to the class, but without changing its internal behavior. Any changes in the code are undesirable. Because of often changing the declaration of the method causes the program to crash in a different place. This rule is particularly important for large projects that many programmers work on. The application of the open/closed principle amounts to the conscious use of composition, inheritance or access modifiers. The source code presented in PHP below violates the OCP policy. Adding a new species will make it necessary to modify the existing AnimalMotion class, which is responsible for movement. In this case, you will have to add another condition. It will make the right move for it depending on the added genre.

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 function move($animal)
{
if(is_a($animal,'Pigeon')) echo 'I am flying!';
else if(is_a($animal,'Chetaah')) echo 'I am running!';
}
}

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

In such a situation, it is best to use a polymorphism. It may be necessary to implement method that causes the movement of animal to each class representing a given species. The following example uses the OCP policy by using the abstract class of Animal. The function implemented in the AnimalMotion class is passed as an argument to the entire $animal object. This object was created within the class of the given species. Thanks to this, the SRP principle is also preserved, because only the AnimalMotion class is responsible for the animal’s movement. Classes responsible for creating animal of a given species, e.g. Cheetah or Pigeon, contain only implementation of the move() method.

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

class Pigeon extends Animal 
{ 
private $flyingSpeed; 

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

public function move()
{
echo 'I am flying';
}
}

class Cheetah extends Animal
{
private $runningSpeed;

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

public function move()
{
echo 'I am running!';
}
}

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

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