Прилагане на интерфейси в ООП в PHP
И така, вече установихме, че интерфейсите са добър начин за контрол на това, че всички необходими методи на класа са реализирани.
Нека разгледаме още един, по-практичен, пример. Нека имаме клас, който ще съхранява масив от обекти-фигури:
<?php
class FiguresCollection
{
private $figures = []; // масив за фигури
}
?>
Нека реализираме в нашия клас метод addFigure
за добавяне на обекти в колекцията:
<?php
class FiguresCollection
{
private $figures = [];
// Параметър се подава обект с фигура:
public function addFigure($figure)
{
$this->figures[] = $figure;
}
}
?>
Очевидно е, че разчитаме на това, че
параметър на метода addFigure ще бъде
подаден обект с фигура. Но за това няма никакъв контрол!
Нека използваме подсказка за типове и
изрично посочим типа на обектите като Figure:
<?php
class FiguresCollection
{
private $figures = [];
public function addFigure(Figure $figure)
{
$this->figures[] = $figure;
}
}
?>
Нека разберем какво направихме.
Ако Figure беше реално съществуващ
клас, то в параметъра на метода бихме могли да
подадем обекти от този клас, както и от
неговите наследници.
При нас обаче Figure е интерфейс.
В този случай подсказката означава, че
параметър на метода могат да бъдат подавани само
обекти от класове, които реализират нашия интерфейс.
Нека опитаме да създадем обект от нашия клас и да добавим в него фигури:
<?php
$figuresCollection = new FiguresCollection;
// Ще добавим няколко квадрата:
$figuresCollection->add(new Quadrate(2));
$figuresCollection->add(new Quadrate(3));
// Ще добавим няколко правоъгълника:
$figuresCollection->add(new Rectangle(2, 3));
$figuresCollection->add(new Rectangle(3, 4));
?>
Опитът да се добави обект от някой друг клас ще доведе до грешка:
<?php
$figuresCollection = new FiguresCollection;
class Test {}; // някакъв друг клас
$figuresCollection->add(new Test); // ще даде грешка
?>
Какво на практика ни дава такъв контрол:
тъй като всички фигури, добавени в колекцията,
реализират интерфейса Figure, можем
да сме сигурни, че всяка от тях ще има метод
getSquare и метод
getPerimeter.
Възможно е в бъдеще освен квадрат и правоъгълник
да се появи, например, и триъгълник. В
този случай и триъгълникът ще има
методи getSquare и
getPerimeter.
На практика това ни дава следното: можем
в класа FiguresCollection да направим,
например, метод getTotalSquare, намиращ
общата площ на фигурите в колекцията. В този метод
ще обхождаме в цикъл масива от фигури и
за всяка фигура ще извикваме
метода getSquare.
Тъй като всяка фигура реализира интерфейса
Figure, можем да сме на 100%
сигурни в това, че всяка фигура ще има
този метод getSquare.
И така, ето реализацията на метода:
<?php
class FiguresCollection
{
private $figures = [];
public function addFigure(Figure $figure)
{
$this->figures[] = $figure;
}
// Ще намерим общата площ:
public function getTotalSquare()
{
$sum = 0;
foreach ($this->figures as $figure) {
$sum += $figure->getSquare(); // използваме метода getSquare
}
return $sum;
}
}
?>
Без да надничате в моя код, реализирайте същия
клас FiguresCollection.
Добавете в класа FiguresCollection
метод getTotalPerimeter за намиране
на общия периметър на всички фигури.