Zastosowanie interfejsów w OOP w PHP
A więc, już ustaliliśmy, że interfejsy są dobrym sposobem kontrolowania tego, że zostały zaimplementowane wszystkie niezbędne metody klasy.
Przyjrzyjmy się kolejnemu, bardziej praktycznemu, przykładowi. Załóżmy, że mamy klasę, która będzie przechowywać tablicę obiektów-figur:
<?php
class FiguresCollection
{
private $figures = []; // tablica na figury
}
?>
Zaimplementujmy w naszej klasie metodę addFigure
do dodawania obiektów do kolekcji:
<?php
class FiguresCollection
{
private $figures = [];
// Parametrem przekazywany jest obiekt z figurą:
public function addFigure($figure)
{
$this->figures[] = $figure;
}
}
?>
Oczywiście, zakładamy, że parametrem metody addFigure będzie
przekazywany obiekt z figurą. Jednak nie ma nad tym żadnej kontroli!
Użyjmy podpowiedzi dla typów i
wyraźnie wskażmy typ obiektów jako Figure:
<?php
class FiguresCollection
{
private $figures = [];
public function addFigure(Figure $figure)
{
$this->figures[] = $figure;
}
}
?>
Zastanówmy się, co zrobiliśmy.
Gdyby Figure był rzeczywiście istniejącą
klasą, to do parametru metody moglibyśmy
przekazać obiekty tej klasy, a także
jej dziedziczących.
U nas jednak Figure to interfejs.
W takim przypadku podpowiedź oznacza, że
parametrem metody mogą być przekazane tylko
obiekty klasy, implementujące nasz interfejs.
Spróbujmy stworzyć obiekt naszej klasy i dodać do niego figury:
<?php
$figuresCollection = new FiguresCollection;
// Dodajmy parę kwadratów:
$figuresCollection->add(new Quadrate(2));
$figuresCollection->add(new Quadrate(3));
// Dodajmy parę prostokątów:
$figuresCollection->add(new Rectangle(2, 3));
$figuresCollection->add(new Rectangle(3, 4));
?>
Próba dodania obiektu jakiejkolwiek innej klasy spowoduje błąd:
<?php
$figuresCollection = new FiguresCollection;
class Test {}; // jakaś inna klasa
$figuresCollection->add(new Test); // zwróci błąd
?>
Co w praktyce daje nam taką kontrolę:
ponieważ wszystkie figury dodane do kolekcji
implementują interfejs Figure, możemy
być pewni, że każda z nich będzie miała metodę
getSquare i metodę
getPerimeter.
Być może w przyszłości oprócz kwadratu i prostokąta
pojawi się, na przykład, jeszcze trójkąt. W
tym przypadku i trójkąt również będzie miał
metody getSquare i
getPerimeter.
W praktyce daje nam to następujące: możemy
w klasie FiguresCollection zrobić,
na przykład, metodę getTotalSquare, znajdującą
całkowite pole figur kolekcji. W tej metodzie
będziemy przechodzić pętlą po tablicy figur i
u każdej figury wywoływać
metodę getSquare.
Ponieważ każda figura implementuje interfejs
Figure, możemy być na 100%
pewni, że każda figura będzie miała
tę metodę getSquare.
A więc, oto implementacja metody:
<?php
class FiguresCollection
{
private $figures = [];
public function addFigure(Figure $figure)
{
$this->figures[] = $figure;
}
// Znajdźmy całkowite pole:
public function getTotalSquare()
{
$sum = 0;
foreach ($this->figures as $figure) {
$sum += $figure->getSquare(); // używamy metody getSquare
}
return $sum;
}
}
?>
Nie podglądając w mój kod zaimplementuj taką
samą klasę FiguresCollection.
Dodaj do klasy FiguresCollection
metodę getTotalPerimeter do znajdowania
sumarycznego obwodu wszystkich figur.