How to replace conditionals with polymorphism
clean code refactoring open close polymorphismLet’s imagine your boss is coming one day and asks you to write some code to calculate the area of a rectangle.
You say ok, that’s easy, and you start first creating a class for a Rectangle
.
class Rectangle {
public $width;
public $height;
public function __construct($width, $height)
{
$this->width = $width;
$this->height = $height;
}
}
Then because you know the principle from OOP (object oriented programming) that claims a class should do only one thing, you create another class for calculating the area for the rectangle. This class will be used as a service class in your project.
class AreaCalculator {
public function calculate($rectangle)
{
return $rectangle->width * $rectangle->height;
}
}
At this moment everything works perfectly, your code is running and your boss is happy. But after a while he tells you
that you have to calculate the area of a circle too. So you go and think how to do this, you first create the
Circle
class and then modify also the AreaCalculator.
class Circle {
public $radius;
public function __construct($radius) {
$this->radius = $radius;
}
}
class AreaCalculator {
public function calculate($shape)
{
if ($shape instanceof Rectangle) {
return $shape->width * $shape->height;
} else {
return $shape->radius * $shape->radius * pi();
}
}
}
At the end you make it, the code is doing what it supposed to do, your boss is happy again. But this isn’t feeling right to you because you know you violated another principle of OOP, the Open Close principle.
And also as you’re expecting, your boss will tell you later that he needs also to calculate the area of a square. You know something doesn’t smell good, and here polymorphism will help you.
Polymorphism is a pattern in OOP which describes how classes can have different behavior while sharing a common interface.
In another words, polymorphism just give us a way to adopt a common interface that we can reference without needing to understand what happens behind the scenes.
Implement polymorphism
In order to ensure that your classes do conform to the polymorphism principle, we can choose between one of the two options of either abstract classes or interfaces.
For our small example we will use an interface Shape
which will be implemented by all shapes your boss needs and
forces you to implement a method calculateArea()
.
interface Shape {
public function calculateArea();
}
The rectangle class implements the Shape
interface by defining the calculateArea()
method with the formula that
calculates the area of a rectangle and the circle also implements the Shape
interface but defining the
calculateArea()
method with the formula for calculating the area of a circle. The result of the polymorphism
implementation on your classes looks like this.
class Rectangle implements Shape {
public $width;
public $height;
public function __construct($width, $height)
{
$this->width = $width;
$this->height = $height;
}
public function calculateArea() {
return $this->width * $this->height;
}
}
class Circle implements Shape {
public $radius;
public function __construct($radius) {
$this->radius = $radius;
}
public function calculateArea() {
return $this->radius * $this->radius * pi();
}
}
Now you can remove the if conditional from the AreaCalculator
service and replace it with just one single line that
you’ll never change when your boss will ask you to calculate the area of a new shape.
class AreaCalculator {
public function calculate(Shape $shape)
{
return $shape->calculateArea();
}
}
$area = new AreaCalculator();
echo $area->calculate(new Rectangle(24, 40)); // 960
echo $area->calculate(new Circle(30)); // 2827.4333882308
So if your boss wants now to calculate the area of a square, all you have to do is to create the Square
class
that implements the shape interface. No more modifications on the AreaCalculator
service.
class Square implements Shape {
public $wight;
public function __construct($wight) {
$this->wight = $wight;
}
public function calculateArea() {
return $this->wight * $this->wight;
}
}
echo $area->calculate(new Square(10)); // 100
Conclusions
This is a very simple principle but a very powerful one. Your code will be so much cleaner and extensible when you’re conforming to the polymorphism principle.
If you liked this post, you can share it on Twitter. Also you can follow me on Github or endorse me on LinkedIn.