Применение интерфейсов

Итак, мы уже выяснили, что интерфейсы хороший способ контролировать то, что реализованы все необходимые методы класса.

Давайте рассмотрим еще один, более практический, пример.

Пусть у нас есть класс 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 для нахождения суммарного периметра всех фигур.