Niedawno miałem dwa wywiady telefoniczne, w których zapytano mnie o różnice między klasą interfejsu a klasą abstrakcyjną. Wyjaśniłem każdy aspekt, o którym mogłem pomyśleć, ale wygląda na to, że czekają, aż wymienię coś konkretnego i nie wiem, co to jest.
Z mojego doświadczenia wynika, że następujące są prawdziwe. Jeśli brakuje jakiegoś ważnego punktu, proszę dać mi znać.
Berło:
Każda metoda zadeklarowana w interfejsie będzie musiała zostać zaimplementowana w podklasie. W interfejsie mogą istnieć tylko zdarzenia, delegaci, właściwości (C #) i metody. Klasa może implementować wiele interfejsów.
Klasa abstrakcyjna:
Podklasa musi implementować tylko metody abstrakcyjne. Klasa Abstract może mieć normalne metody z implementacjami. Klasa abstrakcyjna może również mieć zmienne klasowe obok Zdarzenia, Delegaci, Właściwości i Metody. Klasa może implementować tylko jedną klasę abstrakcyjną tylko z powodu nieistnienia Multi-dziedziczenia w C #.
Po tym wszystkim ankieter zapytał: „Co by było, gdybyś miał klasę abstrakcyjną z tylko abstrakcyjnymi metodami? Czym różni się to od interfejsu?” Nie znałem odpowiedzi, ale myślę, że jest to dziedzictwo, jak wspomniano powyżej, prawda?
Inny ankieter zapytał mnie, co jeśli miałbyś zmienną publiczną w interfejsie, czym by to się różniło niż w klasie abstrakcyjnej? Upierałem się, że nie możesz mieć publicznej zmiennej w interfejsie. Nie wiedziałam, co chciał usłyszeć, ale też nie był zadowolony.
Zobacz także :
źródło
I insisted you can't have a public variable inside an interface.
Myślę, że interfejs może mieć zmienną publiczną. W rzeczywistości zmienne w interfejsie są automatycznie publiczne i ostateczne.Odpowiedzi:
Chociaż twoje pytanie wskazuje, że dotyczy „ogólnego OO”, wydaje się, że naprawdę koncentruje się na użyciu tych terminów w .NET.
W .NET (podobnie jak Java):
Jako ogólne warunki OO różnice niekoniecznie są dobrze zdefiniowane. Na przykład są programiści C ++, którzy mogą posiadać podobne sztywne definicje (interfejsy są ścisłym podzbiorem klas abstrakcyjnych, które nie mogą zawierać implementacji), podczas gdy niektórzy mogą powiedzieć, że klasa abstrakcyjna z niektórymi domyślnymi implementacjami jest nadal interfejsem lub że nie jest abstrakcyjna klasa nadal może definiować interfejs.
Rzeczywiście, istnieje idiom języka C ++ o nazwie Non-Virtual Interface (NVI), w którym metody publiczne są metodami innymi niż wirtualne, które „uderzają” w prywatne metody wirtualne:
źródło
Co powiesz na analogię: kiedy byłem w lotnictwie, poszedłem na szkolenie pilotów i zostałem pilotem USAF (US Air Force). W tym momencie nie miałem kwalifikacji do latania i musiałem uczestniczyć w szkoleniu na typ samolotu. Kiedy się zakwalifikowałem, byłem pilotem (klasa abstrakcyjna) i pilotem C-141 (klasa konkretna). Podczas jednego z moich zadań przydzielono mi dodatkowy obowiązek: funkcjonariusz ds. Bezpieczeństwa. Teraz nadal byłem pilotem i pilotem C-141, ale również pełniłem obowiązki funkcjonariusza ds. Bezpieczeństwa (wdrożyłem, że tak powiem, ISafetyOfficer). Pilot nie musiał być oficerem bezpieczeństwa, inne osoby również mogły to zrobić.
Wszyscy piloci USAF muszą przestrzegać określonych przepisów dla całego lotnictwa, a wszyscy piloci C-141 (lub F-16 lub T-38) są pilotami USAF. Każdy może być oficerem bezpieczeństwa. Podsumowując:
dodano uwagę: miała to być analogia do wyjaśnienia pojęcia, a nie zalecenie dotyczące kodowania. Zobacz różne komentarze poniżej, dyskusja jest interesująca.
źródło
Jay
nie może dziedziczyć po wielu klasach (pilot C-141, pilot F-16 i pilot T-38), czy to znaczy, czyje klasy powinny zostać interfejsami? DziękiMyślę, że odpowiedź, której szukają, to podstawowa lub filozoficzna różnica OPPS.
Dziedziczenie klasy abstrakcyjnej jest używane, gdy klasa pochodna ma podstawowe właściwości i zachowanie klasy abstrakcyjnej. Rodzaj zachowania, które faktycznie określa klasę.
Z drugiej strony dziedziczenie interfejsu jest stosowane, gdy klasy dzielą zachowania peryferyjne, które niekoniecznie definiują klasę pochodną.
Na przykład Samochód i ciężarówka mają wiele podstawowych właściwości i zachowania abstrakcyjnej klasy samochodowej, ale mają też pewne zachowania peryferyjne, takie jak Generowanie układu wydechowego, które mają nawet klasy inne niż samochodowe, takie jak Wiertarki lub PowerGeneratory, i niekoniecznie definiują samochód lub ciężarówkę , więc Samochód, Ciężarówka, Wiertarka i PowerGenerator mogą dzielić ten sam interfejs IExhaust.
źródło
accelerate
jest częścią podstawowego zachowania klasy abstrakcyjnej Automobile, to nie mogę powiedzieć, żeaccelerate
pokazuje charakter umowy . czym jest natura kontraktowa? dlaczego to słowocontract
pojawia się za każdym razem, gdy mówimyinterface
?interface
musi zachowywać się na peryferiach, dlaczegopublic interface List<E> extends Collection<E> {}
jest zaprojektowany do opisania podstawowych zachowańlist
? jest to w rzeczywistości sprzeczne z odpowiedzią prasun. ZarównoCollection<E>
iList<E>
interfejsy tutaj.Krótko: Klasy abstrakcyjne są używane do modelowania hierarchii klas podobnie wyglądających klas (na przykład Zwierzę może być klasą abstrakcyjną, a Człowiek, Lew, Tygrys mogą być klasami pochodnymi)
I
Interfejs służy do komunikacji między 2 podobnymi / niepodobnymi klasami, które nie dbają o typ klasy implementującej interfejs (np. Wysokość może być własnością interfejsu i może być zaimplementowana przez człowieka, budynek, drzewo. Nie ma znaczenia, czy możesz jeść , możesz pływać, możesz umrzeć lub cokolwiek ... to ma znaczenie tylko to, co musisz mieć Wysokość (implementacja w twojej klasie).
źródło
Istnieje kilka innych różnic -
Interfejsy nie mogą mieć żadnych konkretnych implementacji. Mogą to robić abstrakcyjne klasy podstawowe. Pozwala to na zapewnienie konkretnych wdrożeń. Może to pozwolić abstrakcyjnej klasie bazowej na zapewnienie bardziej rygorystycznego kontraktu, a interfejs naprawdę opisuje tylko sposób użycia klasy. (Abstrakcyjna klasa podstawowa może mieć nie-wirtualne elementy definiujące zachowanie, co daje większą kontrolę autorowi klasy podstawowej).
W klasie można zaimplementować więcej niż jeden interfejs. Klasa może wywodzić się tylko z jednej abstrakcyjnej klasy podstawowej. Pozwala to na hierarchię polimorficzną przy użyciu interfejsów, ale nie abstrakcyjnych klas bazowych. Pozwala to również na pseudo-wielokrotne dziedziczenie za pomocą interfejsów.
Abstrakcyjne klasy podstawowe można modyfikować w wersji 2 + bez psucia interfejsu API. Zmiany w interfejsach są przełomowymi zmianami.
[C # /. NET Specific] Interfejsy, w przeciwieństwie do abstrakcyjnych klas bazowych, mogą być stosowane do typów wartości (struktur). Struktury nie mogą dziedziczyć po abstrakcyjnych klasach podstawowych. Pozwala to na stosowanie kontraktów behawioralnych / wytycznych dotyczących użytkowania w odniesieniu do rodzajów wartości.
źródło
Dziedzictwo
Zastanów się nad samochodem i autobusem. Są to dwa różne pojazdy. Ale nadal mają wspólne cechy, takie jak układ kierowniczy, hamulce, biegi, silnik itp.
Tak więc dzięki koncepcji dziedziczenia można to przedstawić następująco ...
Teraz rower ...
I samochód ...
To wszystko dotyczy dziedziczenia . Używamy ich do klasyfikowania obiektów w prostsze formy podstawowe i ich dzieci, jak widzieliśmy powyżej.
Klasy abstrakcyjne
Klasy abstrakcyjne są niekompletnymi obiektami. Aby to zrozumieć, jeszcze raz rozważmy analogię pojazdu.
Pojazd można prowadzić. Dobrze? Ale różne pojazdy są prowadzone na różne sposoby ... Na przykład nie można prowadzić samochodu tak, jak jeździ się rowerem.
Jak więc przedstawić funkcję jazdy pojazdu? Trudniej jest sprawdzić, jaki to pojazd, i prowadzić go własną funkcją; przy dodawaniu nowego typu pojazdu musiałbyś ciągle zmieniać klasę kierowcy.
Nadchodzi rola abstrakcyjnych klas i metod. Możesz zdefiniować metodę napędu jako abstrakcyjną, aby powiedzieć, że każde dziedziczące dziecko musi zaimplementować tę funkcję.
Jeśli więc zmodyfikujesz klasę pojazdu ...
Rower i samochód muszą również określać sposób prowadzenia pojazdu. W przeciwnym razie kod nie zostanie skompilowany i zostanie zgłoszony błąd.
W skrócie ... klasa abstrakcyjna jest częściowo niekompletną klasą z pewnymi niekompletnymi funkcjami, które dziedziczące dzieci muszą określić własne.
Interfejsy Interfejsy są całkowicie niekompletne. Nie mają żadnych właściwości. Wskazują tylko, że dziedziczące dzieci są w stanie coś zrobić ...
Załóżmy, że masz przy sobie różne rodzaje telefonów komórkowych. Każdy z nich ma inne sposoby wykonywania różnych funkcji; Np .: zadzwoń do osoby. Producent telefonu określa, jak to zrobić. Tutaj telefony komórkowe mogą wybrać numer - to znaczy, że można go wybrać. Przedstawmy to jako interfejs.
Tutaj twórca Dialable określa sposób wybierania numeru. Musisz tylko dać mu numer do wybrania.
Używając interfejsów zamiast klas abstrakcyjnych, autor funkcji korzystającej z Dialable nie musi martwić się o swoje właściwości. Np .: Czy ma ekran dotykowy lub klawiaturę, Czy jest to telefon stacjonarny czy komórkowy? Musisz tylko wiedzieć, czy można go wybrać; dziedziczy (lub implementuje) interfejs Dialable.
A co ważniejsze , jeśli któregoś dnia zmienisz Dialable na inny
Możesz być pewien, że kod nadal działa idealnie, ponieważ funkcja, która używa dialable, nie zależy (i nie może) od innych szczegółów niż te określone w interfejsie Dialable. Obie implementują interfejs Dialable i to jedyna rzecz, na której zależy jej funkcja.
Interfejsy są powszechnie używane przez programistów w celu zapewnienia interoperacyjności (używaj zamiennie) między obiektami, o ile mają one wspólną funkcję (podobnie jak możesz zmienić telefon stacjonarny lub komórkowy, o ile wystarczy wybrać numer). Krótko mówiąc, interfejsy są znacznie prostszą wersją klas abstrakcyjnych, bez żadnych właściwości.
Pamiętaj też, że możesz implementować (dziedziczyć) tyle interfejsów, ile chcesz, ale możesz rozszerzać (dziedziczyć) tylko jedną klasę nadrzędną.
Więcej informacji Klasy abstrakcyjne a interfejsy
źródło
Jeśli uważasz, że
java
język OOP odpowiada na to pytanie, wydanie Java 8 powoduje, że niektóre z powyższych odpowiedzi są przestarzałe. Teraz interfejs Java może mieć domyślne metody z konkretną implementacją.Oracle strona dostarcza kluczowych różnic pomiędzy
interface
iabstract
klasę.Rozważ użycie klas abstrakcyjnych, jeśli:
Rozważ użycie interfejsów, jeśli:
Serializable
interfejs.Mówiąc najprościej, chciałbym użyć
interfejs: Aby wdrożyć umowę przez wiele niepowiązanych obiektów
Klasa abstrakcyjna: Aby zaimplementować to samo lub inne zachowanie wśród wielu powiązanych obiektów
Spójrz na przykład kodu, aby zrozumieć wszystko w jasny sposób: Jak powinienem wyjaśnić różnicę między interfejsem a klasą abstrakcyjną?
źródło
Ankieterzy szczekają dziwne drzewo. W przypadku języków takich jak C # i Java jest różnica, ale w innych językach, takich jak C ++, nie ma. Teoria OO nie rozróżnia tych dwóch, a jedynie składnię języka.
Klasa abstrakcyjna to klasa z implementacją i interfejsem (czysto wirtualne metody), która zostanie odziedziczona. Interfejsy zasadniczo nie mają żadnej implementacji, a jedynie czysto wirtualne funkcje.
W języku C # lub Java klasa abstrakcyjna bez żadnej implementacji różni się od interfejsu tylko składnią używaną do dziedziczenia z niego oraz faktem, że można dziedziczyć tylko z jednej.
źródło
Wdrażając interfejsy, uzyskujesz kompozycję (relacje „has-a”) zamiast dziedziczenia (relacje „is-a”). Jest to ważna zasada, o której należy pamiętać, gdy chodzi o takie rzeczy, jak wzorce projektowe, w których należy użyć interfejsów, aby uzyskać kompozycję zachowań zamiast dziedziczenia.
źródło
wyjaśnię szczegóły głębokości interfejsu i klasy abstrakcyjnej. jeśli znasz ogólne informacje o interfejsie i klasie abstrakcyjnej, wtedy przyjdzie ci do głowy pierwsze pytanie, kiedy powinniśmy użyć interfejsu, a kiedy powinniśmy użyć klasy abstrakcyjnej. Więc sprawdź poniżej wyjaśnienie klasy Interface i Abstract.
Kiedy powinniśmy używać interfejsu?
jeśli nie wiesz o implementacji, tylko mamy specyfikację wymagań, wówczas korzystamy z interfejsu
Kiedy powinniśmy używać klasy abstrakcyjnej?
jeśli znasz implementację, ale nie całkowicie (częściowo implementację), to wybieramy klasę Abstract.
Berło
każda metoda domyślnie public abstract oznacza, że interfejs jest w 100% czystym abstraktem.
Abstrakcyjny
może mieć metodę Konkretną i Metodę Abstrakcyjną, czyli Metodę Konkretną, która ma implementację w klasie Abstrakcyjnej, Klasa abstrakcyjna to klasa, która jest zadeklarowana jako abstrakcyjna - może zawierać metody abstrakcyjne lub nie.
Berło
Nie możemy zadeklarować interfejsu jako prywatny, chroniony
P: Dlaczego nie ogłaszamy, że interfejs jest prywatny i chroniony?
Ponieważ domyślnie metoda interfejsu jest publicznie abstrakcyjna, dlatego też nie ogłaszamy, że interfejs jest prywatny i chroniony.
Metoda interfejsu
również nie możemy zadeklarować interfejsu jako prywatny, chroniony, końcowy, statyczny, zsynchronizowany, natywny .....
Podam powód: dlaczego nie deklarujemy metody zsynchronizowanej, ponieważ nie możemy stworzyć obiektu interfejsu, a synchronizacja jest pracą na obiekcie, a więc powód, dla którego nie deklarujemy metody zsynchronizowanej Koncepcja przejściowa również nie ma zastosowania, ponieważ praca przejściowa z synchronizacją.
Abstrakcyjny
chętnie używamy z publicznymi, prywatnymi statycznymi statycznymi .... oznacza, że żadne ograniczenia nie mają zastosowania w sposób abstrakcyjny.
Berło
Zmienne są zadeklarowane w interfejsie jako domyślny publiczny statyczny finał, dlatego też nie jesteśmy zadeklarowani jako zmienni prywatni, chronieni.
Zmienny modyfikator nie ma również zastosowania w interfejsie, ponieważ zmienna interfejsu jest domyślnie publiczną statyczną zmienną końcową i końcową, nie można zmienić wartości po przypisaniu wartości do zmiennej, a po zadeklarowaniu zmiennej w interfejsie należy ją przypisać.
Zmienna zmienna ciągle się zmienia, więc jest przeciwna. do końca dlatego nie używamy zmiennych zmiennych w interfejsie.
Abstrakcyjny
Zmienna abstrakcyjna nie ma potrzeby deklarowania publicznego statycznego końcowego
mam nadzieję, że ten artykuł będzie przydatny.
źródło
Abstract class must have at lease one abstract method.
Możliwe jest posiadanie klasy Abstract bez metody Abstract, o ile ją zaimplementujesz. ODNIESIENIE:An abstract class is a class that is declared abstract—it may or may not include abstract methods.
ŹRÓDŁO ODNIESIENIA: docs.oracle.com/javase/tutorial/java/IandI/abstract.htmlMówiąc koncepcyjnie, utrzymanie implementacji specyficznych dla języka, zasad, korzyści i osiągnięcie dowolnego celu programowania przy użyciu dowolnego lub obu, może lub nie może mieć kodu / danych / właściwości, bla bla, pojedynczego lub wielokrotnego dziedziczenia, wszystko na boku
1- Klasa abstrakcyjna (lub czysto abstrakcyjna) Klasa służy do implementacji hierarchii. Jeśli obiekty biznesowe wyglądają nieco strukturalnie podobnie, reprezentując jedynie relację rodzic-dziecko (hierarchia), wówczas zostaną użyte klasy dziedziczenia / abstrakcyjne. Jeśli twój model biznesowy nie ma hierarchii, nie należy stosować dziedziczenia (tutaj nie mówię o logice programowania, np. Niektóre wzorce projektowe wymagają dziedziczenia). Koncepcyjnie klasa abstrakcyjna to metoda implementacji hierarchii modelu biznesowego w OOP, nie ma ona nic wspólnego z interfejsami, w rzeczywistości porównywanie klasy abstrakcyjnej z interfejsem jest bez znaczenia, ponieważ obie są koncepcyjnie całkowicie różnymi rzeczami, w wywiadach jest proszony o sprawdzenie pojęć, ponieważ oba wydają się zapewniać nieco taką samą funkcjonalność, jeśli chodzi o implementację, a my programiści zwykle kładziemy większy nacisk na kodowanie. [Pamiętaj również, że abstrakcja różni się od klasy abstrakcyjnej].
2 - Interfejs to umowa, pełna funkcjonalność biznesowa reprezentowana przez jeden lub więcej zestaw funkcji. Dlatego jest zaimplementowany, a nie odziedziczony. Obiekt biznesowy (część hierarchii lub nie) może mieć dowolną liczbę pełnych funkcji biznesowych. Nie ma to nic wspólnego z klasami abstrakcyjnymi, ale ogólnie z dziedziczeniem. Na przykład człowiek może URUCHOMIĆ, słoń może URUCHOMIĆ, ptak może URUCHOMIĆ, i tak dalej, wszystkie te obiekty o różnej hierarchii implementują interfejs RUN lub interfejs EAT lub SPEAK. Nie wchodź w implementację, ponieważ możesz zaimplementować ją jako posiadającą klasy abstrakcyjne dla każdego typu implementującego te interfejsy. Obiekt dowolnej hierarchii może mieć funkcjonalność (interfejs), która nie ma nic wspólnego z jego hierarchią.
Uważam, że interfejsy nie zostały wymyślone w celu osiągnięcia wielu spadków lub ujawnienia publicznego zachowania, podobnie czyste klasy abstrakcyjne nie zastępują interfejsów, ale interfejs jest funkcją, którą może wykonywać obiekt (poprzez funkcje tego interfejsu), a klasa abstrakcyjna reprezentuje element nadrzędny hierarchii w celu utworzenia elementów podrzędnych o podstawowej strukturze (właściwość + funkcjonalność) elementu nadrzędnego
Kiedy zostaniesz zapytany o różnicę, tak naprawdę jest to różnica konceptualna, a nie różnica w implementacji specyficznej dla języka, chyba że zostaniesz wyraźnie zapytany.
Uważam, że obaj ankieterzy oczekiwali jednej linii prostej różnicy między tymi dwoma, a kiedy ci się nie udało, próbowali doprowadzić cię do tej różnicy, wdrażając JEDEN jako INNY
źródło
Dla .Net,
Twoja odpowiedź na Drugi ankieter jest również odpowiedzią na pierwszą ... Klasy abstrakcyjne mogą mieć implementację, ORAZ, interfejsy nie mogą ...
EDYCJA: Z drugiej strony, nie użyłbym nawet frazy „podklasa” (lub „dziedziczenie”) do opisania klas, które są „zdefiniowane do implementacji” interfejsu. Dla mnie interfejs jest definicją kontraktu, z którym klasa musi się zgadzać, jeśli została zdefiniowana w celu „implementacji” tego interfejsu. Niczego nie dziedziczy ... Musisz sam wszystko dodać.
źródło
Interfejs : należy używać, jeśli chcesz sugerować regułę dla komponentów, które mogą, ale nie muszą być ze sobą powiązane
Plusy:
Cons:
Klasa abstrakcyjna : należy stosować tam, gdzie chcesz mieć podstawowe lub domyślne zachowanie lub implementację powiązanych ze sobą komponentów
Plusy:
Cons:
źródło
Myślę, że nie podobała im się twoja odpowiedź, ponieważ podałeś różnice techniczne zamiast projektowych. To pytanie jest dla mnie jak troll. W rzeczywistości interfejsy i klasy abstrakcyjne mają zupełnie inny charakter, więc nie można ich tak naprawdę porównać. Dam ci moją wizję roli interfejsu i roli klasy abstrakcyjnej.
Interfejs: służy do zapewnienia kontraktu i niskiego sprzężenia między klasami w celu uzyskania łatwiejszej w utrzymaniu, skalowalnej i testowalnej aplikacji.
Klasa abstrakcyjna: służy tylko do faktoryzacji kodu między klasami o tej samej odpowiedzialności. Zauważ, że jest to główny powód, dla którego wielokrotne dziedziczenie jest złą rzeczą w OOP, ponieważ klasa nie powinna obsługiwać wielu obowiązków ( zamiast tego użyj kompozycji ).
Interfejsy mają więc prawdziwą rolę architektoniczną, podczas gdy klasy abstrakcyjne są prawie tylko szczegółem implementacji (jeśli używasz go prawidłowo).
źródło
Dokumenty wyraźnie mówią, że jeśli klasa abstrakcyjna zawiera tylko deklaracje metody abstrakcyjnej, powinna zostać zadeklarowana jako interfejs.
Zmienne w interfejsach są domyślnie publiczne statyczne i końcowe. Pytanie może zostać sformułowane tak, jakby wszystkie zmienne w klasie abstrakcyjnej były publiczne? Cóż, nadal mogą być niestatyczne i nieostateczne, w przeciwieństwie do zmiennych w interfejsach.
Na koniec dodałbym jeszcze jeden punkt do tych wymienionych powyżej - klasy abstrakcyjne są nadal klasami i mieszczą się w jednym drzewie dziedziczenia, podczas gdy interfejsy mogą występować w wielu elementach dziedziczenia.
źródło
To jest moja opinia.
źródło
Skopiowane z CLR przez C # przez Jeffrey Richter ...
Często słyszę pytanie: „Czy powinienem zaprojektować typ podstawowy czy interfejs?” Odpowiedź nie zawsze jest jednoznaczna.
Oto kilka wskazówek, które mogą ci pomóc:
■■ Relacja IS-A vs. CAN-DO Typ może dziedziczyć tylko jedną implementację. Jeśli typ pochodny nie może twierdzić o związku IS-A z typem podstawowym, nie należy używać typu podstawowego; użyj interfejsu. Interfejsy sugerują związek CAN-DO. Jeśli wydaje się, że funkcjonalność CAN-DO należy do różnych typów obiektów, użyj interfejsu. Na przykład typ może konwertować instancje samego siebie na inny typ (IConvertible), typ może serializować instancję samego siebie (ISerializable) itp. Uwaga: typy wartości muszą pochodzić z System.ValueType, a zatem nie można ich wyprowadzić z dowolnej klasy bazowej. W takim przypadku musisz użyć relacji CAN-DO i zdefiniować interfejs.
■■ Łatwość użycia Generalnie łatwiej jest programistom zdefiniować nowy typ na podstawie typu podstawowego niż wdrożyć wszystkie metody interfejsu. Typ podstawowy może zapewniać wiele funkcji, więc typ pochodny prawdopodobnie wymaga jedynie stosunkowo niewielkich modyfikacji swojego zachowania. Jeśli podasz interfejs, nowy typ musi implementować wszystkie elementy.
■■ Spójne wdrożenie Bez względu na to, jak dobrze dokumentowana jest umowa dotycząca interfejsu, jest bardzo mało prawdopodobne, aby wszyscy w 100% poprawnie zrealizowali umowę. W rzeczywistości COM cierpi z powodu tego bardzo problemu, dlatego niektóre obiekty COM działają poprawnie tylko z Microsoft Word lub Windows Internet Explorer. Zapewniając typ podstawowy z dobrą domyślną implementacją, zaczynasz od użycia typu, który działa i jest dobrze przetestowany; możesz następnie modyfikować części wymagające modyfikacji.
■■ Wersjonowanie Jeśli dodasz metodę do typu podstawowego, typ pochodny odziedziczy nową metodę, zaczniesz od użycia typu, który działa, a kod źródłowy użytkownika nie musi nawet zostać ponownie skompilowany. Dodanie nowego elementu do interfejsu zmusza spadkobiercę interfejsu do zmiany kodu źródłowego i ponownej kompilacji.
źródło
abstract class
również zachowanie.Interfejs definiuje umowę dotyczącą usługi lub zestawu usług. Zapewniają one polimorfizm w sposób poziomy, ponieważ dwie całkowicie niezwiązane klasy mogą implementować ten sam interfejs, ale mogą być używane zamiennie jako parametr typu interfejsu, który implementują, ponieważ obie klasy obiecały spełnić zestaw usług zdefiniowanych przez interfejs. Interfejsy nie zawierają szczegółów implementacji.
Klasa abstrakcyjna definiuje strukturę podstawową dla swoich podklas i opcjonalnie częściową implementację. Klasy abstrakcyjne zapewniają polimorfizm w sposób pionowy, ale kierunkowy, w ten sposób, że każda klasa dziedzicząca klasę abstrakcyjną może być traktowana jako instancja tej klasy abstrakcyjnej, ale nie na odwrót. Klasy abstrakcyjne mogą i często zawierają szczegóły implementacji, ale nie mogą być tworzone samodzielnie - tylko ich podklasy mogą być „odnawiane”.
C # pozwala również na dziedziczenie interfejsu.
źródło
Większość odpowiedzi skupia się na technicznej różnicy między klasą abstrakcyjną a interfejsem, ale ponieważ technicznie interfejs jest zasadniczo rodzajem abstrakcyjnej klasy (jedna bez żadnych danych ani implementacji), myślę, że różnica koncepcyjna jest o wiele bardziej interesująca i może to być to, co ankieterzy szukają.
Interfejs jest umowa . Określa: „w ten sposób będziemy ze sobą rozmawiać”. Nie może mieć żadnej implementacji, ponieważ nie powinna mieć żadnej implementacji. To umowa. To jest jak
.h
pliki nagłówkowe w C.Streszczenie Klasa jest niepełna realizacja . Klasa może, ale nie musi, implementować interfejs, a klasa abstrakcyjna nie musi go całkowicie implementować. Klasa abstrakcyjna bez żadnej implementacji jest bezużyteczna, ale całkowicie legalna.
Zasadniczo każda klasa, abstrakcyjna lub nie, dotyczy tego, czym jest , podczas gdy interfejs dotyczy tego, jak z niej korzystasz . Na przykład:
Animal
może być klasą abstrakcyjną implementującą niektóre podstawowe funkcje metaboliczne i określającą abstrakcyjne metody oddychania i poruszania się bez podania implementacji, ponieważ nie ma pojęcia, czy powinien oddychać przez skrzela lub płuca i czy lata, pływa, chodzi lub czołga się.Mount
, z drugiej strony, może być interfejsem, który określa, że możesz jeździć na zwierzęciu, nie wiedząc, jakie to zwierzę (lub czy w ogóle jest zwierzęciem!).Fakt, że za kulisami interfejs jest w zasadzie klasą abstrakcyjną z jedynie abstrakcyjnymi metodami, nie ma znaczenia. Pod względem koncepcyjnym pełnią one zupełnie inne role.
źródło
Jak zapewne posiadasz wiedzę teoretyczną od ekspertów, nie powtarzam zbyt wielu słów tutaj, pozwól mi wyjaśnić na prostym przykładzie, gdzie możemy użyć / nie możemy użyć
Interface
iAbstract class
.Zastanów się, czy projektujesz aplikację, aby wyświetlić listę wszystkich funkcji samochodów. W różnych punktach konieczne jest wspólne dziedziczenie, ponieważ niektóre właściwości, takie jak DigitalFuelMeter, klimatyzacja, regulacja siedzeń itp. Są wspólne dla wszystkich samochodów. Podobnie, potrzebujemy dziedziczenia tylko dla niektórych klas, ponieważ niektóre właściwości, takie jak układ hamulcowy (ABS, EBD) mają zastosowanie tylko do niektórych samochodów.
Poniższa klasa działa jako klasa bazowa dla wszystkich samochodów:
Rozważ, że mamy osobną klasę dla każdego samochodu.
Rozważmy, że potrzebujemy metody dziedziczenia technologii hamowania dla samochodów Verna i Cruze (nie dotyczy Alto). Chociaż oba wykorzystują technologię hamowania, „technologia” jest inna. Tworzymy więc klasę abstrakcyjną, w której metoda zostanie zadeklarowana jako Abstrakcyjna i powinna zostać zaimplementowana w jej klasach potomnych.
Teraz staramy się odziedziczyć tę abstrakcyjną klasę, a typ układu hamulcowego jest zaimplementowany w Verna i Cruze:
Widzisz problem w dwóch powyższych klasach? Dziedziczą po wielu klasach, na które C # .Net nie pozwala, mimo że metoda jest zaimplementowana w elementach potomnych. Nadchodzi potrzeba interfejsu.
A wdrożenie podano poniżej:
Teraz Verna i Cruze mogą osiągnąć wielokrotne dziedzictwo dzięki własnym technologiom hamowania za pomocą interfejsu.
źródło
Interfejsy są lekkim sposobem wymuszenia określonego zachowania. To jeden ze sposobów myślenia.
źródło
Te odpowiedzi są za długie.
Interfejsy służą do definiowania zachowań.
Klasy abstrakcyjne służą do definiowania samej rzeczy, w tym jej zachowań. Dlatego czasami tworzymy klasę abstrakcyjną z pewnymi dodatkowymi właściwościami dziedziczącymi interfejs.
Wyjaśnia to również, dlaczego Java obsługuje tylko pojedyncze dziedziczenie dla klas, ale nie nakłada żadnych ograniczeń na interfejsy. Ponieważ konkretny obiekt nie może być różnymi rzeczami, ale może mieć różne zachowania.
źródło
1) Interfejs może być postrzegany jako czysta klasa abstrakcyjna, jest taki sam, ale mimo to nie jest taki sam, jeśli chodzi o implementację interfejsu i dziedziczenie po klasie abstrakcyjnej. Kiedy dziedziczysz po tej czystej abstrakcyjnej klasie, definiujesz hierarchię -> dziedziczenie, jeśli zaimplementujesz interfejs, nie jesteś i możesz zaimplementować tyle interfejsów, ile chcesz, ale możesz dziedziczyć tylko z jednej klasy.
2) Możesz zdefiniować właściwość w interfejsie, więc klasa implementująca ten interfejs musi mieć tę właściwość.
Na przykład:
Klasa implementująca ten interfejs musi mieć taką właściwość.
źródło
Chociaż to pytanie jest dość stare, chciałbym dodać jeszcze jedną rzecz na korzyść interfejsów:
Interfejsy można wstrzykiwać za pomocą dowolnego narzędzia wstrzykiwania zależności, w którym wstrzykiwanie klasy abstrakcyjnej jest obsługiwane przez bardzo nieliczne.
źródło
Z innej mojej odpowiedzi , głównie dotyczącej tego, kiedy użyć jednej kontra drugiej:
źródło
Typy interfejsów a abstrakcyjne klasy podstawowe
Na podstawie książki Pro C # 5.0 i .NET 4.5 Framework .
Typ interfejsu może wydawać się bardzo podobny do abstrakcyjnej klasy bazowej. Przypomnij sobie, że gdy klasa jest oznaczona jako abstrakcyjna, może zdefiniować dowolną liczbę elementów abstrakcyjnych, aby zapewnić interfejs polimorficzny dla wszystkich typów pochodnych. Jednak nawet gdy klasa definiuje zestaw elementów abstrakcyjnych, może również dowolnie definiować dowolną liczbę konstruktorów, dane pól, elementy nieabstrakcyjne (z implementacją) i tak dalej. Z drugiej strony interfejsy zawierają tylko abstrakcyjne definicje elementów. Interfejs polimorficzny ustanowiony przez abstrakcyjną klasę nadrzędną podlega jednemu głównemu ograniczeniu, ponieważ tylko typy pochodne obsługują elementy zdefiniowane przez abstrakcyjnego rodzica. Jednak w większych systemach oprogramowania bardzo często rozwija się wiele hierarchii klas, które nie mają wspólnego elementu nadrzędnego poza System.Object. Biorąc pod uwagę, że elementy abstrakcyjne w abstrakcyjnej klasie bazowej dotyczą tylko typów pochodnych, nie mamy możliwości skonfigurowania typów w różnych hierarchiach w celu obsługi tego samego interfejsu polimorficznego. Jako przykład załóżmy, że zdefiniowałeś następującą klasę abstrakcyjną:
Biorąc pod uwagę tę definicję, tylko członkowie, którzy rozszerzają CloneableType, mogą obsługiwać metodę Clone (). Jeśli utworzysz nowy zestaw klas, które nie rozszerzają tej klasy podstawowej, nie możesz uzyskać interfejsu polimorficznego. Możesz także pamiętać, że C # nie obsługuje wielokrotnego dziedziczenia klas. Dlatego jeśli chcesz utworzyć MiniVan, który jest samochodem i CloneableType, nie możesz tego zrobić:
Jak można się domyślić, na ratunek przychodzą typy interfejsów. Po zdefiniowaniu interfejsu można go wdrożyć w dowolnej klasie lub strukturze, w dowolnej hierarchii, w dowolnej przestrzeni nazw lub w dowolnym zestawie (napisanym w dowolnym języku programowania .NET). Jak widać, interfejsy są wysoce polimorficzne. Rozważ standardowy interfejs .NET o nazwie ICloneable, zdefiniowany w przestrzeni nazw System. Ten interfejs definiuje pojedynczą metodę o nazwie Clone ():
źródło
Odpowiedź na drugie pytanie:
public
zmienna zdefiniowana winterface
jeststatic final
domyślnie, podczas gdypublic
zmienna wabstract
klasie jest zmienną instancji.źródło
Z pewnością ważne jest, aby zrozumieć zachowanie interfejsu i klasy abstrakcyjnej w OOP (oraz sposób, w jaki języki je obsługują), ale myślę, że ważne jest również, aby zrozumieć, co dokładnie oznacza każdy termin. Czy możesz sobie wyobrazić, że
if
polecenie nie działa dokładnie w znaczeniu tego terminu? Ponadto w rzeczywistości niektóre języki zmniejszają, a nawet bardziej, różnice między interfejsem a streszczeniem ... jeśli przypadkiem któregoś dnia oba terminy działają prawie identycznie, przynajmniej możesz sam określić, gdzie (i dlaczego) którykolwiek z nich powinien być używany do.Jeśli przeczytasz niektóre słowniki i inne czcionki, możesz znaleźć inne znaczenia dla tego samego terminu, ale mając pewne wspólne definicje. Myślę, że te dwa znaczenia, które znalazłem na tej stronie, są naprawdę, bardzo dobre i odpowiednie.
Berło:
Abstrakcyjny:
Przykład:
Kupiłeś samochód, który potrzebuje paliwa.
Twój model samochodu jest
XYZ
gatunkiemABC
, więc jest konkretnym samochodem, konkretnym przykładem samochodu. Samochód nie jest prawdziwym przedmiotem. W rzeczywistości jest to abstrakcyjny zestaw standardów (cech) służących do tworzenia określonego obiektu. Krótko mówiąc, Car jest klasą abstrakcyjną , jest „czymś, co skupia w sobie podstawowe cechy czegoś szerszego lub bardziej ogólnego” .Jedyne paliwo, które odpowiada specyfikacji samochodu, powinno być użyte do napełnienia zbiornika samochodu. W rzeczywistości nic nie ogranicza Cię do wlewania paliwa, ale silnik będzie działał poprawnie tylko z określonym paliwem, więc lepiej jest przestrzegać jego wymagań. Wymagania mówią, że akceptuje, podobnie jak inne samochody tego samego gatunku
ABC
, standardowy zestaw paliwa.W widoku obiektowym paliwo dla gatunku
ABC
nie powinno być deklarowane jako klasa, ponieważ nie ma konkretnego paliwa dla określonego gatunku samochodu. Chociaż twój samochód może zaakceptować paliwo abstrakcyjne lub Fuel Vehicle, musisz pamiętać, że tylko niektóre z istniejących paliw samochodowych spełniają specyfikację, które spełniają wymagania zawarte w instrukcji obsługi samochodu. Krótko mówiąc, powinni wdrożyć interfejsABCGenreFuel
, który „... pozwala na efektywne koordynowanie oddzielnych, a czasem niekompatybilnych elementów” .Uzupełnienie
Ponadto uważam, że należy pamiętać o znaczeniu terminu „klasa” (z tej samej strony, o której wcześniej wspomniano):
Klasa:
W ten sposób klasa (lub klasa abstrakcyjna) powinna reprezentować nie tylko wspólne atrybuty (jak interfejs), ale jakąś grupę o wspólnych atrybutach. Interfejs nie musi reprezentować żadnego rodzaju. Musi reprezentować wspólne atrybuty. W ten sposób myślę, że klasy i klasy abstrakcyjne mogą być używane do przedstawiania rzeczy, które nie powinny często zmieniać jego aspektów, jak człowiek będący ssakiem, ponieważ reprezentuje on pewne rodzaje. Rodzaje nie powinny się tak często zmieniać.
źródło
Z perspektywy kodowania
Interfejs może zastąpić klasę abstrakcyjną, jeśli klasa abstrakcyjna ma tylko metody abstrakcyjne. W przeciwnym razie zmiana klasy abstrakcyjnej na interfejs oznacza, że stracisz możliwość ponownego użycia kodu, który zapewnia dziedziczenie.
Z perspektywy projektowania
Zachowaj go jako klasę abstrakcyjną, jeśli jest to relacja „Jest”, a potrzebujesz podzestawu lub całej funkcjonalności. Zachowaj go jako interfejs, jeśli jest to relacja „powinna zrobić”.
Zdecyduj, czego potrzebujesz: tylko egzekwowanie polisy lub ponowne użycie kodu ORAZ polisa.
źródło
Kilka innych różnic:
Klasy abstrakcyjne mogą mieć metody statyczne, właściwości, pola itp. I operatory, interfejsy nie. Operator rzutowania pozwala na rzutowanie do / z klasy abstrakcyjnej, ale nie pozwala na rzutowanie do / z interfejsu.
Tak więc możesz samodzielnie używać klasy abstrakcyjnej, nawet jeśli nigdy nie jest ona zaimplementowana (poprzez elementy statyczne) i nie możesz w żaden sposób korzystać z interfejsu samodzielnie.
źródło