Czy jest jakaś różnica między interfejsami a klasami abstrakcyjnymi, które mają tylko metody abstrakcyjne?

9

Powiedzmy, że mamy klasę abstrakcyjną i niech ta klasa ma tylko abstrakcyjne metody. Czy ta klasa abstrakcyjna różni się od interfejsu, który ma tylko te same metody?

Chcę wiedzieć, czy istnieją jakieś różnice zarówno filozoficzne, obiektywne, jak i podstawowe w implementacji języka programowania między klasą abstrakcyjną zawierającą tylko elementy abstrakcyjne i równoważny interfejs?

yfklon
źródło
który język?
kevin cline
o ile wiem, na twoje pytanie udzielana jest podwójnie : tu i tutaj . I te dwie odpowiedzi są niezależne od języka, nic specyficznego dla C # tam
komnata
3
@blank Nie zgodziłem się ze stanem duplikatu zastosowanym do twojego pytania, więc otworzyłem je ponownie. Następnie zredagowałem twoje pytanie, aby wyjaśnić, o co, jak sądzę, pytasz.
wałek klonowy

Odpowiedzi:

22

Technicznie różnice nie są tak naprawdę znaczące, ale koncepcyjnie są to zupełnie różne rzeczy, co prowadzi do różnic technicznych, o których wspominali inni.

Abstrakcyjna superklasa jest dokładnie taka, jak się wydaje, jest to typowy typ, który jest wspólny dla wielu innych typów, takich jak Koty i Psy to Zwierzęta.

Interfejs jest również dokładnie tak, jak brzmi, jest interfejsem, przez który inne klasy mogą komunikować się z obiektem. Jeśli chcesz zrobić Cat Walk, nic ci nie jest, bo Cat implementuje interfejs CanWalk. To samo dotyczy Jaszczurki, choć chodzą zupełnie inaczej. Z drugiej strony Snake nie implementuje CanWalk, więc nie możesz mu powiedzieć Walk. W międzyczasie Jaszczurka i Wąż (lub bardziej wyraźne podklasy - nie jestem ekspertem) mogą zarówno zrzucić skórę, a tym samym wdrożyć CanShed, podczas gdy Kot nie mógł tego zrobić.

Ale wciąż są zwierzętami i mają pewne wspólne właściwości, takie jak to, czy są żywe czy martwe.

Dlatego wszystkie metody interfejsu muszą być zaimplementowane jako publiczne (lub jawnie w języku C #). Bo jaki jest sens interfejsu, który jest ukryty przed interfejsem klasy z obiektem? Dlatego też możesz mieć wiele interfejsów do obiektu, nawet jeśli język nie obsługuje wielokrotnego dziedziczenia.

Wracając do pytania, kiedy patrzysz na to w ten sposób, bardzo rzadko istnieje powód, by mieć całkowicie abstrakcyjną nadklasę.

pdr
źródło
4
+1, chociaż koty zrzucają w znacznie bardziej irytujący sposób niż węże lub jaszczurki.
Matthew Flynn
Technicznie: Metody abstrakcyjne można zabezpieczyć. Metody interfejsu nie mogą.
Jacques Koorts
19

W większości języków OOP klasa implementująca może wywodzić się tylko z jednej klasy abstrakcyjnej, ale implementować wiele interfejsów.

herzmeister
źródło
3
większość? które liczysz? Większość języków OOP, które znam, nie ma interfejsów ani klas abstrakcyjnych. C ++ ma tylko klasy abstrakcyjne.
kevin cline
10
@kevincline: prawdopodobnie C #, Java i VB.NET.
tdammers
1
@kevincline, myślę, że brakuje tylko „posiadania obu”. IIRC, w Adzie motywem interfejsu było to, że projektanci nie chcieli ogólnej funkcji wielokrotnego dziedziczenia, ale szczególny przypadek interfejsu uznano za zbyt ważny, aby go nie udostępnić.
AProgrammer 19.04.13
@tdammers: LOL. To był żart, prawda?
kevin cline,
3

W języku takim jak C ++, który umożliwia wielokrotne dziedziczenie i nie ma interfejsów, klasy abstrakcyjne, w których wszystkie metody są abstrakcyjne, mogą służyć jako interfejsy. Nie pracowałem tak bardzo z C ++, ale sądzę, że wielokrotne dziedziczenie może powodować problemy, gdy istnieją metody o tej samej nazwie w klasach podstawowych.

W językach takich jak PHP i C # interfejsy umożliwiają osiągnięcie podobnego polimorfizmu, chociaż nie lubię nazywać go „dziedziczeniem”, ponieważ istnieje koncepcyjna różnica między dziedziczeniem klasy abstrakcyjnej a implementacją interfejsu. Interfejsy usuwają problem konfliktu, ponieważ same nie zapewniają implementacji.

Interfejs służy jako umowa ze światem zewnętrznym, podczas gdy klasa abstrakcyjna może zapewnić implementację, chociaż jeśli zostanie użyta do „sfałszowania” interfejsu, najprawdopodobniej nie.

Główna różnica koncepcyjna polega na tym, że gdy klasa dziedziczy inną klasę (abstrakcyjną lub nie), istnieje relacja „jest”, więc a Carjest a Vehiclei Dogjest Animal. W przypadku interfejsu liczy się to, co robi obiekt. Więc zarówno Cari Dogmoże, jak Move()i konsument wie o tym, ponieważ wdrażają Movable, ale Samochód zdecydowanie nie jest Dogani Animal. I implementacja ruchu będzie inna (koła vs nogi), ale kod zużywający się nie obchodzi i nie powinien się przejmować. Interfejsy dotyczą raczej zużywającego się kodu, a nie implementacji.

Najważniejsze jest to, że jeśli masz interfejsy w swoim wybranym języku, używaj ich do rzeczy, dla których są. Jeśli nie (jak w C ++), możesz je sfałszować za pomocą czysto abstrakcyjnych klas.

Ivan Pintar
źródło
Interfejs jest typem, tak więc można mieć IAnimal oba Dogi Cat .
Amy Blankenship,
Mógłbyś, ale moim zdaniem, interfejsy dotyczą zachowania wystawionego na świat zewnętrzny, a nie tyle tego, czym są przedmioty. Dziedzictwo implikuje, że coś jest rodzajem czegoś innego (Cat is an Animal). Interfejs mówi po prostu, co ten obiekt może zrobić. Dlatego lubię mówić, że coś „implementuje”, a nie „dziedziczy” interfejs, co powiedziałaby większość ludzi .Net, z którymi pracowałem (chyba, ponieważ składnia jest taka sama dla dziedziczenia i implementacji).
Ivan Pintar
2

Klasy abstrakcyjne mogą zawierać metody chronione abstrakcyjnie (w językach, z którymi pracuję), w interfejsach metody są zwykle zawsze publiczne. Czy ta różnica pozwala na użyteczne wykorzystanie, nie wiem.

Edytuj Najpierw pomyślałem, że prywatna abstrakcyjna metoda nie ma sensu, ale teraz przypomniałem sobie, że można jej użyć, aby upewnić się, że ta metoda nigdy nie zostanie wywołana. W ten sposób można zapobiec wywoływaniu konstruktora kopii obiektu.

Tomasz
źródło
1
Chronione metody wirtualne (z możliwością przesłonięcia) mogą być przydatne dla klas, które są częścią frameworka lub coś w tym rodzaju. W ten sposób zapewniają, że niestandardowy kod w klasie, która dziedziczy abstrakt, zapewnia tę funkcjonalność. Chociaż można to również osiągnąć przez odziedziczenie interfejsu w klasie podstawowej, ale nie zaimplementowanie jego metod
Ivan Pintar
Tak, myślałem o czymś takim, ale nie mam z tym żadnego doświadczenia, więc nie mogłem tego ocenić. Dzięki za wkład.
Thomas
Tylko uwaga. W niektórych językach prywatne metody wirtualne można zastąpić w klasach pochodnych.
Johan Boulé
2

Tak, są różne. W przeciwnym razie projektanci języków nie przedstawiliby obu. Znam dwa języki, które oddzielają klasy i interfejsy: Java i C #, zmutowany klon Java. Projektanci stworzyli interfejsy, aby uniknąć obsługi dziedziczenia wielu klas. Większość innych języków obsługuje dziedziczenie wielu klas, w związku z czym nie rozdziela klas i interfejsów.

Kevin Cline
źródło
2

Myślę, że główna różnica polega na tym, że: w klasie abstrakcyjnej - nawet jeśli wszystkie metody są abstrakcyjne, mogą nadal zapewniać elementy danych (zmienne instancji) i trochę kodu do klas, które ją implementują (w postaci prywatnych metod lub konstruktorów), bloki statyczne; wykonując część pracy dla podklas i pomagając im we wdrożeniu.

Jeden pozytywny efekt uboczny: kod jest w jednym miejscu, więc w jednym miejscu można wprowadzić poprawki. podklasy mogą po prostu wywołać metodę superklasy, a następnie zrobić coś innego lub nic, jeśli działania superklasy są wystarczające dla ich przypadku. Superklasa chce, aby każda podklasa podjęła tę decyzję, dlatego oznaczyła całą swoją implementację jako abstrakcyjną (niektóre też mogą być puste)

Nie dotyczy pytania: ale posiadanie interfejsów oznacza, że ​​jedna klasa może realizować dwie różne umowy. To przewaga interfejsu nad abstrakcyjną superklasą

tgkprog
źródło
1
Czy metody abstrakcyjne nie są zdefiniowane bez żadnej implementacji i pozostawiają implementację klasom dziedziczącym?
Ivan Pintar,
Tak po prawej stronie to chyba jej tylko zmienne, konstruktorów i metod statycznych i prywatnych, jeśli liczyć te
tgkprog
@ Pinetree, w praktyce przez większość czasu będziesz potrzebować przynajmniej trochę „prawdziwego” kodu w swoich klasach abstrakcyjnych (przynajmniej w języku, którego używam, który nie ma specjalnej konstrukcji dla klas abstrakcyjnych).
Amy Blankenship
@AmyBlankenship tak, większość klas abstrakcyjnych ma „prawdziwy” kod (po to są). Ale miałem na myśli metody abstrakcyjne, w kontekście czysto abstrakcyjnej klasy, która służy jako interfejs w języku takim jak C ++, który nie ma interfejsów.
Ivan Pintar