Dlaczego potrzebujesz interfejsu, jeśli istnieją już abstrakcyjne klasy?
Aby zapobiec wielokrotnemu dziedziczeniu (może powodować wiele znanych problemów).
Jeden z takich problemów:
„Problem diamentów” (czasem określany jako „śmiertelny diament śmierci”) jest dwuznacznością, która pojawia się, gdy dwie klasy B i C dziedziczą po A, a klasa D dziedziczy zarówno po B, jak i C. Jeśli istnieje metoda w A, która B i C zostały zastąpione, a D nie zastępuje go, to którą wersję metody dziedziczy D: wersję B, czy wersję C?
Źródło: https://en.wikipedia.org/wiki/Multiple_inheritance#The_diamond_problem
Dlaczego / Kiedy korzystać z interfejsu?
Przykład ... Wszystkie samochody na świecie mają ten sam interfejs (metody) ... AccelerationPedalIsOnTheRight()
,BrakePedalISOnTheLeft()
. Wyobraź sobie, że każda marka samochodów miałaby te „metody” inne niż inna marka. BMW miałoby Hamulce po prawej stronie, a Honda miałaby hamulce po lewej stronie koła. Ludzie będą musieli nauczyć się, jak działają te „metody” za każdym razem, gdy kupują inną markę samochodu. Dlatego dobrze jest mieć ten sam interfejs w wielu „miejscach”.
Co robi dla ciebie interfejs (dlaczego ktoś miałby go używać)? Interfejs zapobiega popełnianiu „błędów” (zapewnia, że wszystkie klasy, które implementują określony interfejs, będą miały wszystkie metody dostępne w interfejsie).
// Methods inside this interface must be implemented in all classes which implement this interface.
interface IPersonService
{
public function Create($personObject);
}
class MySqlPerson implements IPersonService
{
public function Create($personObject)
{
// Create a new person in MySql database.
}
}
class MongoPerson implements IPersonService
{
public function Create($personObject)
{
// Mongo database creates a new person differently then MySQL does. But the code outside of this method doesn't care how a person will be added to the database, all it has to know is that the method Create() has 1 parameter (the person object).
}
}
W ten sposób Create()
metoda będzie zawsze używana w ten sam sposób. Nie ma znaczenia, czy korzystamy z MySqlPerson
klasy, czy zMongoPerson
klasy. Sposób w jaki korzystamy z metody pozostaje taki sam (interfejs pozostaje taki sam).
Na przykład będzie używany w ten sposób (wszędzie w naszym kodzie):
new MySqlPerson()->Create($personObject);
new MongoPerson()->Create($personObject);
W ten sposób coś takiego nie może się wydarzyć:
new MySqlPerson()->Create($personObject)
new MongoPerson()->Create($personsName, $personsAge);
O wiele łatwiej jest zapamiętać jeden interfejs i używać wszędzie tego samego interfejsu, niż wielu różnych.
W ten sposób wnętrze Create()
metody może być różne dla różnych klas, bez wpływu na kod „zewnętrzny”, który wywołuje tę metodę. Cały zewnętrzny kod musi wiedzieć, że metoda Create()
ma 1 parametr ( $personObject
), ponieważ w ten sposób zewnętrzny kod użyje / wywoła metodę. Zewnętrzny kod nie obchodzi, co dzieje się w metodzie; musi tylko wiedzieć, jak go użyć / nazwać.
Możesz to zrobić także bez interfejsu, ale jeśli używasz interfejsu, jest on „bezpieczniejszy” (ponieważ zapobiega popełnianiu błędów). Interfejs zapewnia, że metoda Create()
będzie miała tę samą sygnaturę (te same typy i tę samą liczbę parametrów) we wszystkich klasach, które implementują interfejs. W ten sposób możesz być pewien, że DOWOLNA klasa, która implementuje IPersonService
interfejs, będzie miała metodę Create()
(w tym przykładzie) i będzie potrzebowała tylko 1 parametru ( $personObject
) do wywołania / użycia.
Klasa implementująca interfejs musi implementować wszystkie metody, które interfejs wykonuje / posiada.
Mam nadzieję, że nie powtórzyłem się zbyt często.