Итак, мы уже выяснили, что интерфейсы хороший способ контролировать то, что реализованы все необходимые методы класса.
Давайте рассмотрим еще один, более практический, пример.
Пусть у нас есть класс FiguresCollection, который будет хранить в себе массив объектов-фигур:
<?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 - это интерфейс. В таком случае подсказка обозначает то, что параметром метода могут быт переданы только объекты класса, реализующих интерфейс Figure.
Давайте попробуем создать объект класса FiguresCollection и добавить в него фигуры:
<?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, находящий полную площадь фигур коллекции.
При этом в методе 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 для нахождения суммарного периметра всех фигур.