Proszę wyjaśnić, kiedy powinienem używać PHP, interface
a kiedy powinienem abstract class
?
Jak mogę zmienić swoje abstract class
konto na interface
?
Proszę wyjaśnić, kiedy powinienem używać PHP, interface
a kiedy powinienem abstract class
?
Jak mogę zmienić swoje abstract class
konto na interface
?
Odpowiedzi:
Użyj interfejsu, gdy chcesz zmusić programistów pracujących w twoim systemie (włączając ciebie) do wdrożenia określonej liczby metod w klasach, które będą budować.
Użyj klasy abstrakcyjnej, jeśli chcesz zmusić programistów pracujących w twoim systemie (włączając ciebie) do zaimplementowania określonej liczby metod i chcesz podać podstawowe metody, które pomogą im rozwinąć klasy potomne.
Inną rzeczą, o której należy pamiętać, jest to, że klasy klientów mogą rozszerzać tylko jedną klasę abstrakcyjną, podczas gdy mogą implementować wiele interfejsów. Jeśli więc definiujesz swoje umowy dotyczące zachowania w klasach abstrakcyjnych, oznacza to, że każda klasa potomna może być zgodna tylko z jedną umową. Czasami jest to dobra rzecz, gdy chcesz zmusić programistów do korzystania z określonej ścieżki. Innym razem byłoby źle. Wyobraź sobie, że interfejsy PHP Countable i Iterator były klasami abstrakcyjnymi zamiast interfejsów.
Jednym z powszechnych podejść, gdy nie masz pewności, którą drogą wybrać (jak wspomniano poniżej, jest utworzenie interfejsu, a następnie zaimplementowanie tego interfejsu przez klasę abstrakcyjną.
Różnice między an Abstract Class
a Interface
:
Klasy abstrakcyjne
Klasa abstrakcyjna może zapewnić pewną funkcjonalność, a resztę pozostawić dla klasy pochodnej .
Klasa pochodna może, ale nie musi, zastępować konkretne funkcje zdefiniowane w klasie bazowej.
Klasa potomna wywodząca się z klasy abstrakcyjnej powinna być logicznie powiązana.
Berło
Interfejs nie może zawierać żadnej funkcjonalności . Zawiera tylko definicje metod.
Klasa pochodna MUSI zapewnić kod dla wszystkich metod zdefiniowanych w interfejsie .
Całkowicie różne i niepowiązane klasy można logicznie pogrupować za pomocą interfejsu.
abstract class X implements Y
i class X implements Y
?
abstract class X implements Y
oświadczasz, że zbiorcza funkcjonalność X powinna być zaimplementowana w klasie pochodnej oraz że zarówno klasa abstrakcyjna, jak i pochodna muszą zawierać funkcje zdefiniowane w Y, podczas gdy class X implements Y
implikuje to tylko, że klasa X musi zawierać funkcje zdefiniowane w Y. Jeśli twój interfejs Y nie jest przeznaczony do implementacji przez żadną inną klasę niż XI, tak naprawdę pominąłby definiowanie Y jako interfejs i implementowałby funkcje w Y jako publiczną / chronioną / prywatną funkcję abstrakcyjną, aby upewnić się, że są one zaimplementowane w klasie pochodnej.
Dlaczego warto korzystać z klas abstrakcyjnych? Oto prosty przykład. Powiedzmy, że mamy następujący kod:
<?php
class Fruit {
private $color;
public function eat() {
// chew
}
public function setColor($c) {
$this->color = $c;
}
}
class Apple extends Fruit {
public function eat() {
// chew until core
}
}
class Orange extends Fruit {
public function eat() {
// peeling
// chew
}
}
Teraz daję ci jabłko, a ty jesz. Jak to smakuje? Smakuje jak jabłko.
<?php
$apple = new Apple();
$apple->eat();
// Now I give you a fruit.
$fruit = new Fruit();
$fruit->eat();
Jak to smakuje? Cóż, to nie ma większego sensu, więc nie powinieneś być w stanie tego zrobić. Uzyskuje się to poprzez streszczenie klasy Fruit oraz metodę jedzenia wewnątrz niej.
<?php
abstract class Fruit {
private $color;
abstract public function eat(){}
public function setColor($c) {
$this->color = $c;
}
}
?>
Klasa abstrakcyjna jest jak interfejs, ale można zdefiniować metody w klasie abstrakcyjnej, podczas gdy w interfejsie wszystkie są abstrakcyjne. Klasy abstrakcyjne mogą mieć zarówno metody puste, jak i pracujące / konkretne. W interfejsach funkcje tam zdefiniowane nie mogą mieć ciała. W klasach abstrakcyjnych potrafią.
Przykład ze świata rzeczywistego:
<?php
abstract class person {
public $LastName;
public $FirstName;
public $BirthDate;
abstract protected function write_info();
}
final class employee extends person{
public $EmployeeNumber;
public $DateHired;
public function write_info(){
//sql codes here
echo "Writing ". $this->LastName . "'s info to emloyee dbase table <br>";
}
}
final class student extends person{
public $StudentNumber;
public $CourseName;
public function write_info(){
//sql codes here
echo "Writing ". $this->LastName . "'s info to student dbase table <br>";
}
}
///----------
$personA = new employee;
$personB = new student;
$personA->FirstName="Joe";
$personA->LastName="Sbody";
$personB->FirstName="Ben";
$personB->LastName="Dover";
$personA->write_info();
// Writing Sbody's info to emloyee dbase table
$personB->write_info();
// Writing Dover's info to student dbase table
What does that taste like? Well, it doesn't make much sense, so you shouldn't be able to do that.
Teraz znam streszczenie!
final
słowo kluczowe? Świetny post, dzięki.
Najlepszą praktyką jest użycie interfejsu do określenia kontraktu i klasy abstrakcyjnej jako tylko jednej jego realizacji. Ta klasa abstrakcyjna może wypełnić wiele schematu, dzięki czemu możesz utworzyć implementację, po prostu nadpisując to, czego potrzebujesz lub czego chcesz, bez zmuszania Cię do użycia konkretnej implementacji.
Żeby wrzucić to do miksu, ale jak Cletus wspomniał o użyciu interfejsu w połączeniu z klasą abstrakcyjną, często używam interfejsu do wyjaśnienia mojego myślenia projektowego.
Na przykład:
<?php
class parser implements parserDecoratorPattern {
//...
}
W ten sposób każdy, kto czyta mój kod (i kto wie, co to jest wzorzec dekoratora), będzie od razu wiedział a) w jaki sposób buduję mój parser oraz b) będzie mógł zobaczyć, jakie metody są stosowane do implementacji wzorca dekoratora.
Poza tym mogę być tutaj nie będący programistą Java / C ++ / etc, ale typy danych mogą się tutaj bawić. Twoje obiekty są pewnego rodzaju, a kiedy je rozprowadzasz, ma to znaczenie programowe. Przeniesienie elementów objętych kontraktem do interfejsu dyktuje tylko typy zwracane przez metody, ale nie typ podstawowy klasy, która je implementuje.
Jest późno i nie mogę wymyślić lepszego przykładu kodu psudo, ale oto:
<?php
interface TelevisionControls {};
class Remote implements TelevisionControls {};
class Spouse implements TelevisionControls {};
Spouse spouse = new Spouse();
Remote remote = new Remote();
isSameType = (bool)(remote == spouse)
Główną różnicą jest to, że klasa abstrakcyjna może zawierać domyślną implementację, podczas gdy interfejs nie.
Interfejs to umowa o zachowaniu bez jakiegokolwiek wdrożenia.
Chciałbym również dodać tutaj, że tylko dlatego, że jakikolwiek inny język OO ma jakieś interfejsy i abstrakcja, nie oznacza, że mają takie samo znaczenie i cel jak w PHP. Używanie abstrakcji / interfejsów jest nieco inne, podczas gdy interfejsy w PHP nie mają w rzeczywistości żadnej funkcji. Są one używane jedynie ze względów semantycznych i związanych ze schematem. Chodzi o to, aby projekt był jak najbardziej elastyczny, możliwy do rozszerzenia i bezpieczny dla przyszłych rozszerzeń, niezależnie od tego, czy programista ma później zupełnie inny plan użytkowania, czy nie.
Jeśli Twój angielski nie jest językiem ojczystym, możesz sprawdzić, czym tak naprawdę jest abstrakcja i interfejsy. I szukaj też synonimów.
A to może ci pomóc jako metaforę:
BERŁO
Powiedzmy, że piec nowy rodzaj ciasta z truskawkami i wymyśliłeś przepis opisujący składniki i etapy. Tylko Ty wiesz, dlaczego smakuje tak dobrze, a Twoi goście to lubią. Następnie decydujesz się opublikować swój przepis, aby inne osoby również mogły spróbować tego ciasta.
Chodzi o to, że
- zrobić to dobrze
- zachować ostrożność
- zapobiegać sytuacjom, które mogłyby się popsuć (np. zbyt dużo truskawek lub czegoś takiego)
- ułatwić ludziom, którzy to wypróbowali
- powiedzieć ci, jak długo trzeba robić (np. mieszanie) )
- aby powiedzieć, które rzeczy MOŻESZ zrobić, ale NIE MUSISZ
Właśnie to opisuje interfejsy. Jest to przewodnik, zestaw instrukcji, które przestrzegają treści przepisu. Tak samo, jakbyś tworzył projekt w PHP i chcesz podać kod na GitHub lub ze znajomymi lub czymkolwiek innym. Interfejs to, co ludzie mogą robić, a czego nie. Reguły, które ją trzymają - jeśli nie zastosujesz się do niej, cała konstrukcja zostanie zepsuta.
ABSTRAKCJA
Aby kontynuować tę metaforę tutaj ... wyobraź sobie, że tym razem jesteś gościem jedzącym to ciasto. Następnie próbujesz teraz tego ciasta, korzystając z przepisu. Ale chcesz dodać nowe składniki lub zmienić / pominąć kroki opisane w przepisie. Co dalej? Zaplanuj inną wersję tego ciasta. Tym razem z czarnymi jagodami, a nie słomkowymi i kremem waniliowym ... pyszne.
To właśnie można rozważyć rozszerzenie oryginalnego ciasta. Zasadniczo wykonujesz jej abstrakcję, tworząc nowy przepis, ponieważ jest on inny. Ma kilka nowych kroków i inne składniki. Jednak wersja z czarnymi jagodami ma pewne części, które przejęłaś od oryginału - są to podstawowe kroki, które musi mieć każdy rodzaj tego ciasta. Podobnie jak składniki mleka - właśnie to ma każda klasa pochodna.
Teraz chcesz wymienić składniki i kroki, MUSZĄ one zostać zdefiniowane w nowej wersji tego ciasta. Są to abstrakcyjne metody, które należy zdefiniować dla nowego ciasta, ponieważ powinien on zawierać owoce, ale które? Tym razem bierzesz czarne jagody. Gotowy.
Proszę, rozszerzyłeś ciasto, podążyłeś za interfejsem i wyodrębniłeś z niego kroki i składniki.
Aby dodać do niektórych i tak doskonałych odpowiedzi:
Klasy abstrakcyjne pozwalają na pewien stopień implementacji, interfejsy są czystymi szablonami. Interfejs może jedynie definiować funkcjonalność , nigdy nie może go wdrożyć.
Każda klasa, która implementuje interfejs, zobowiązuje się do wdrożenia wszystkich zdefiniowanych przez siebie metod, w przeciwnym razie musi zostać zadeklarowana jako abstrakcyjna.
Interfejsy mogą pomóc w zarządzaniu faktem, że podobnie jak Java, PHP nie obsługuje wielokrotnego dziedziczenia. Klasa PHP może rozszerzyć tylko jednego rodzica. Możesz jednak złożyć obietnicę klasy zaimplementowania dowolnej liczby interfejsów.
type: dla każdego implementowanego interfejsu klasa przyjmuje odpowiedni typ. Ponieważ każda klasa może implementować interfejs (lub więcej interfejsów), interfejsy skutecznie łączą typy, które w innym przypadku nie są ze sobą powiązane.
klasa może zarówno rozszerzać nadklasę, jak i implementować dowolną liczbę interfejsów:
class SubClass extends ParentClass implements Interface1, Interface2 {
// ...
}
Proszę wyjaśnić, kiedy powinienem użyć interfejsu, a kiedy powinienem użyć klasy abstrakcyjnej?
Użyj interfejsu, jeśli potrzebujesz tylko szablonu bez implementacji, a chcesz mieć pewność, że każda klasa, która implementuje ten interfejs, będzie miała takie same metody jak każda inna klasa, która go implementuje (przynajmniej).
Użyj klasy abstrakcyjnej, jeśli chcesz utworzyć podstawę dla innych obiektów (klasa częściowo zbudowana). Klasa rozszerzająca klasę abstrakcyjną będzie używać niektórych właściwości lub metod zdefiniowanych / zaimplementowanych:
<?php
// interface
class X implements Y { } // this is saying that "X" agrees to speak language "Y" with your code.
// abstract class
class X extends Y { } // this is saying that "X" is going to complete the partial class "Y".
?>
Jak mogę zmienić swoją klasę abstrakcyjną na interfejs?
Oto uproszczony przypadek / przykład. Wyjmij wszystkie szczegóły implementacji. Na przykład zmień klasę abstrakcyjną z:
abstract class ClassToBuildUpon {
public function doSomething() {
echo 'Did something.';
}
}
do:
interface ClassToBuildUpon {
public function doSomething();
}
Z filozoficznego punktu widzenia:
Klasa abstrakcyjna reprezentuje relację „to”. Powiedzmy, że mam owoce, no cóż, miałbym klasę abstrakcyjną Fruit, która dzieli wspólną odpowiedzialność i wspólne zachowanie.
Interfejs reprezentuje relację „należy zrobić”. Interfejs, moim zdaniem (który jest zdaniem młodszego programisty), powinien być nazwany przez akcję lub coś zbliżonego do akcji (Przepraszam, nie mogę znaleźć słowa, nie jestem rodzimym językiem angielskim) powiedzmy IEatable. Wiesz, że można go zjeść, ale nie wiesz, co jesz.
Z punktu widzenia kodowania:
Jeśli twoje obiekty mają zduplikowany kod, oznacza to, że mają one wspólne zachowanie, co oznacza, że możesz potrzebować abstrakcyjnej klasy do ponownego użycia kodu, czego nie można zrobić z interfejsem.
Kolejna różnica polega na tym, że obiekt może implementować tyle interfejsów, ile potrzebujesz, ale możesz mieć tylko jedną klasę abstrakcyjną z powodu „problemu z diamentem” (sprawdź tutaj, aby dowiedzieć się, dlaczego! Http://en.wikipedia.org/wiki/ Multiple_inheritance # The_diamond_problem )
Prawdopodobnie zapominam o niektórych punktach, ale mam nadzieję, że to wyjaśni.
PS: Odpowiedź „należy” / „powinna zrobić” pochodzi od odpowiedzi Viveka Vermaniego. Nie chciałem kraść jego odpowiedzi, tylko po to, aby ponownie użyć terminów, ponieważ je lubiłem!
Różnice techniczne między klasą abstrakcyjną a interfejsem są już dokładnie wymienione w innych odpowiedziach. Chcę dodać wyjaśnienie wyboru między klasą a interfejsem podczas pisania kodu ze względu na programowanie obiektowe.
Klasa powinna reprezentować byt, podczas gdy interfejs powinien reprezentować zachowanie.
Weźmy przykład. Monitor komputerowy jest bytem i powinien być reprezentowany jako klasa.
class Monitor{
private int monitorNo;
}
Został zaprojektowany w celu zapewnienia interfejsu wyświetlacza, więc funkcjonalność powinna być zdefiniowana przez interfejs.
interface Display{
void display();
}
Jest wiele innych rzeczy do rozważenia, jak wyjaśniono w innych odpowiedziach, ale jest to najbardziej podstawowa rzecz, którą większość ludzi ignoruje podczas kodowania.
PHP
Chciałem tylko dodać przykład, kiedy możesz potrzebować obu. Obecnie piszę procedurę obsługi plików powiązaną z modelem bazy danych w rozwiązaniu ERP ogólnego zastosowania.
W ten sposób otrzymuję wiele szablonów dla różnych plików i wspólny zestaw metod interfejsu z wyraźnym rozróżnieniem. Interfejs podaje poprawną analogię do metod dostępu zamiast tych, które byłyby w przypadku podstawowej klasy abstrakcyjnej.
W dalszej kolejności, gdy będę tworzyć adaptery dla różnych usług przechowywania plików, ta implementacja pozwoli na użycie interfejsu gdzie indziej w zupełnie innych kontekstach.
abstract
iinterface
zajęcia, twój post wyjaśnił wszystko.