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?
Odpowiedzi:
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ę.
źródło
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.
źródło
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
Car
jest aVehicle
iDog
jestAnimal
. W przypadku interfejsu liczy się to, co robi obiekt. Więc zarównoCar
iDog
może, jakMove()
i konsument wie o tym, ponieważ wdrażająMovable
, ale Samochód zdecydowanie nie jestDog
aniAnimal
. 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.
źródło
Dog
iCat
są .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.
źródło
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.
źródło
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ą
źródło