To może być ogólne pytanie dotyczące OOP. Chciałem dokonać ogólnego porównania interfejsu z klasą abstrakcyjną na podstawie ich użycia.
Kiedy chciałoby się użyć interfejsu, a kiedy klasy abstrakcyjnej ?
oop
inheritance
interface
abstract-class
Chirantan
źródło
źródło
Odpowiedzi:
Napisałem o tym artykuł:
Klasy abstrakcyjne i interfejsy
Zreasumowanie:
Kiedy mówimy o klasach abstrakcyjnych, definiujemy cechy typu obiektu; określając, czym jest obiekt .
Kiedy mówimy o interfejsie i definiujemy możliwości, które obiecujemy zapewnić, mówimy o zawarciu umowy o tym, co może zrobić obiekt.
źródło
Interfaces do not express something like "a Doberman is a type of dog and every dog can walk" but more like "this thing can walk"
. DziękujęUse abstract classes and inheritance if you can make the statement “A is a B”. Use interfaces if you can make the statement “A is capable of [doing] as”
Klasa abstrakcyjna może mieć stan współdzielony lub funkcjonalność. Interfejs to tylko obietnica zapewniająca stan lub funkcjonalność. Dobra klasa abstrakcyjna zmniejszy ilość kodu, który trzeba przepisać, ponieważ można udostępnić jego funkcjonalność lub stan. Interfejs nie ma zdefiniowanych informacji do udostępnienia
źródło
Osobiście prawie nigdy nie muszę pisać klas abstrakcyjnych.
Najczęściej widzę, że klasy abstrakcyjne są używane (źle), ponieważ autor klasy abstrakcyjnej używa wzorca „Metoda szablonu”.
Problem z „metodą szablonów” polega na tym, że prawie zawsze jest ona w pewnym stopniu ponownie uruchamiana - klasa „pochodna” wie nie tylko o „abstrakcyjnej” metodzie swojej klasy bazowej, którą implementuje, ale także o metodach publicznych klasy podstawowej , mimo że w większości przypadków nie trzeba do nich dzwonić.
(Zbyt uproszczony) przykład:
Tak więc tutaj autor tej klasy napisał ogólny algorytm i chce, aby ludzie go używali, „specjalizując się”, zapewniając własne „zaczepy” - w tym przypadku metodę „porównania”.
Tak więc zamierzone użycie jest mniej więcej takie:
Problem polega na tym, że nadmiernie połączyłeś dwie koncepcje:
W powyższym kodzie teoretycznie autor metody „porównaj” może ponownie wywołać metodę superklasy „Sortuj” ... nawet jeśli w praktyce nigdy nie będzie tego chciał ani nie musiał.
Cena, którą płacisz za to niepotrzebne sprzężenie, polega na tym, że trudno jest zmienić nadklasę, aw większości języków OO nie można jej zmienić w czasie wykonywania.
Alternatywną metodą jest użycie zamiast tego wzorca projektowego „Strategia”:
Więc zauważ teraz: wszystko, co mamy, to interfejsy i konkretne implementacje tych interfejsów. W praktyce tak naprawdę nie potrzebujesz niczego więcej, aby wykonać projekt OO na wysokim poziomie.
Aby „ukryć” fakt, że zaimplementowaliśmy „sortowanie nazw” za pomocą klasy „QuickSort” i „NameComparator”, możemy gdzieś napisać metodę fabryczną:
Za każdym razem, gdy masz klasę abstrakcyjną, możesz to zrobić ... nawet jeśli istnieje naturalna relacja ponownego wejścia między klasą podstawową i pochodną, zwykle opłaca się je wyrazić.
Ostatnia myśl: wszystko, co zrobiliśmy powyżej, to „skomponowanie” funkcji „NameSorting” za pomocą funkcji „QuickSort” i funkcji „NameComparison” ... w funkcjonalnym języku programowania ten styl programowania staje się jeszcze bardziej naturalny, z mniejszym kodem.
źródło
Jeśli patrzysz na java jako język OOP,
„ Interfejs nie zapewnia implementacji metody ” nie jest już ważny w przypadku uruchomienia Java 8. Teraz Java zapewnia implementację interfejsu dla metod domyślnych.
Mówiąc najprościej, chciałbym użyć
interfejs: Aby wdrożyć umowę przez wiele niepowiązanych obiektów. Zapewnia funkcję „ HAS A ”.
Klasa abstrakcyjna: Aby zaimplementować to samo lub inne zachowanie wśród wielu powiązanych obiektów. Ustanawiarelację„ JEST A ”.
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.Przykład:
Klasa abstrakcyjna ( relacja IS A )
Reader to klasa abstrakcyjna.
BufferedReader to
Reader
FileReader to
Reader
FileReader
iBufferedReader
są wykorzystywane do wspólnego celu: Odczytywanie danych i są one powiązane poprzezReader
klasę.Interfejs ( funkcja HAS A )
Serializable to interfejs.
Załóżmy, że masz dwie klasy aplikacji, które implementują
Serializable
interfejsEmployee implements Serializable
Game implements Serializable
Tutaj nie można ustanowić żadnej relacji poprzez
Serializable
interfejs międzyEmployee
iGame
, które są przeznaczone do różnych celów. Oba są w stanie szeregować stan, a porównanie kończy się na tym.Spójrz na te posty:
Jak powinienem wyjaśnić różnicę między interfejsem a klasą abstrakcyjną?
źródło
OK, po tym, jak sam to „wymamrotałem” - tutaj jest to w kategoriach laika (możesz mnie poprawić, jeśli się mylę) - Wiem, że ten temat jest przestarzały, ale ktoś inny może się na niego natknąć pewnego dnia ...
Klasy abstrakcyjne umożliwiają tworzenie schematu i pozwalają dodatkowo KONSTRUKOWAĆ (implementować) właściwości i metody, które mają WSZYSTKIE potomkowie.
Z drugiej strony interfejs pozwala tylko zadeklarować, że chcesz, aby właściwości i / lub metody o danej nazwie istniały we wszystkich klasach, które je implementują - ale nie określa, w jaki sposób powinieneś je wdrożyć. Ponadto klasa może implementować WIELE interfejsów, ale może rozszerzyć tylko JEDNĄ klasę abstrakcyjną. Interfejs to bardziej narzędzie architektoniczne wysokiego poziomu (które staje się bardziej zrozumiałe, jeśli zaczniesz rozumieć wzorce projektowe) - Streszczenie ma stopę w obu obozach i może również wykonywać niektóre brudne prace.
Po co używać jednego na drugim? Pierwszy pozwala na bardziej konkretną definicję potomków - drugi pozwala na większy polimorfizm . Ten ostatni punkt jest ważny dla końcowego użytkownika / kodera, który może wykorzystać te informacje do implementacji AP I (nterface) w różnych kombinacjach / kształtach w zależności od potrzeb.
Myślę, że był to dla mnie moment „żarówka” - myślę o interfejsach mniej z perspektywy autora, a więcej z koderem pochodzącym z późniejszego łańcucha, który dodaje implementację do projektu lub rozszerza API.
źródło
Moje dwa centy:
Interfejs zasadniczo definiuje umowę, do której musi się stosować każda klasa implementująca (implementująca elementy interfejsu). Nie zawiera żadnego kodu.
Z drugiej strony klasa abstrakcyjna może zawierać kod i mogą istnieć pewne metody oznaczone jako abstrakcyjne, które klasa dziedzicząca musi zaimplementować.
Rzadkie sytuacje, w których korzystałem z klas abstrakcyjnych, polegają na tym, że mam domyślną funkcjonalność, której dziedziczenie może nie być interesujące w przypadku przesłonięcia, powiedzmy abstrakcyjnej klasy bazowej, z której dziedziczą niektóre klasy specjalistyczne.
Przykład (bardzo prymitywny jeden!): Rozważmy klasy bazowej o nazwie klienta, który ma abstrakcyjnych metod, takich jak
CalculatePayment()
,CalculateRewardPoints()
i pewne metody abstrakcyjne, takie jakGetName()
,SavePaymentDetails()
.Wyspecjalizowane klasy, takie jak
RegularCustomer
iGoldCustomer
odziedziczą poCustomer
klasie podstawowej i implementują własną logikęCalculatePayment()
iCalculateRewardPoints()
metody, ale ponownie wykorzystują metodyGetName()
iSavePaymentDetails()
.Możesz dodać więcej funkcji do klasy abstrakcyjnej (czyli metod nieabstrakcyjnych) bez wpływu na klasy potomne, które korzystały ze starszej wersji. Podczas gdy dodawanie metod do interfejsu wpłynęłoby na wszystkie klasy implementujące go, ponieważ musiałyby one teraz implementować nowo dodane elementy interfejsu.
Klasa abstrakcyjna ze wszystkimi elementami abstrakcyjnymi byłaby podobna do interfejsu.
źródło
Kiedy robić to, co jest bardzo proste, jeśli masz jasną koncepcję.
Klasy abstrakcyjne można uzyskać, natomiast interfejsy można zaimplementować. Istnieje pewna różnica między nimi. Kiedy wyprowadzasz klasę abstrakcyjną, związek między klasą pochodną a klasą podstawową jest relacją „to”. np. pies to zwierzę, owca to zwierzę, co oznacza, że klasa pochodna dziedziczy niektóre właściwości z klasy podstawowej.
Natomiast w przypadku implementacji interfejsów relacja jest „może być”. np. Pies może być psem szpiegowskim. Pies może być psem cyrkowym. Pies może być psem wyścigowym. Co oznacza, że wdrażasz określone metody uzyskania czegoś.
Mam nadzieję, że wszystko jasne.
źródło
1. Jeśli tworzysz coś, co zapewnia wspólną funkcjonalność niepowiązanym klasom, użyj interfejsu.
2. Jeśli tworzysz coś dla obiektów blisko powiązanych w hierarchii, użyj klasy abstrakcyjnej.
źródło
Napisałem artykuł o tym, kiedy użyć klasy abstrakcyjnej, a kiedy użyć interfejsu. Jest o wiele więcej różnic między nimi niż „jeden IS-A ... i jeden CAN-DO…”. Dla mnie są to odpowiedzi w puszkach. Podaję kilka powodów, dla których warto użyć jednego z nich. Mam nadzieję, że to pomoże.
http://codeofdoom.com/wordpress/2009/02/12/learn-this-when-to-use-an-abstract-class-and-an-interface/
źródło
Myślę, że najbardziej zwięzły sposób to:
Wspólne właściwości => klasa abstrakcyjna.
Wspólna funkcjonalność => interfejs.
I mówiąc mniej zwięźle ...
Przykład klasy abstrakcyjnej:
Ponieważ zwierzęta mają wspólną właściwość - w tym przypadku liczbę nóg - warto stworzyć klasę abstrakcyjną zawierającą tę wspólną właściwość. Pozwala nam to również napisać wspólny kod, który działa na tej właściwości. Na przykład:
Przykład interfejsu:
Zauważ, że Vuvuzelas i Samochody to zupełnie inne rzeczy, ale mają wspólną funkcjonalność: wydawanie dźwięków. Dlatego interfejs ma tutaj sens. Ponadto pozwoli programistom grupować rzeczy, które wydają dźwięki razem, we wspólnym interfejsie -
IMakeSound
w tym przypadku. Za pomocą tego projektu możesz napisać następujący kod:Czy możesz powiedzieć, co by to dało?
Na koniec możesz połączyć te dwa elementy.
Połączony przykład:
Tutaj wymagamy, aby wszyscy
BaseAnimal
wydawali dźwięki, ale nie znamy jeszcze jego implementacji. W takim przypadku możemy wyodrębnić implementację interfejsu i przekazać jej implementację do jego podklas.Ostatni punkt, pamiętasz, jak w przykładzie klasy abstrakcyjnej mogliśmy operować na wspólnych właściwościach różnych obiektów, aw przykładzie interfejsu mogliśmy wywoływać wspólną funkcjonalność różnych obiektów? W tym ostatnim przykładzie moglibyśmy zrobić jedno i drugie.
źródło
Kiedy preferować klasę abstrakcyjną zamiast interfejsu?
Kiedy preferować interfejs zamiast klasy abstrakcyjnej?
źródło
Klasy mogą dziedziczyć tylko jedną klasę podstawową, więc jeśli chcesz użyć klas abstrakcyjnych w celu zapewnienia polimorfizmu grupie klas, wszystkie muszą dziedziczyć po tej klasie. Klasy abstrakcyjne mogą również zapewniać członków, które zostały już zaimplementowane. Dlatego możesz zapewnić pewną ilość identycznej funkcjonalności z klasą abstrakcyjną, ale nie możesz z interfejsem.
Oto kilka zaleceń, które pomogą Ci zdecydować, czy użyć interfejsu, czy klasy abstrakcyjnej, aby zapewnić polimorfizm komponentów.
Skopiowano z:
http://msdn.microsoft.com/en-us/library/scsyfw1d%28v=vs.71%29.aspx
źródło
Rozważ użycie klas abstrakcyjnych, jeśli któreś z poniższych stwierdzeń dotyczy Twojej sytuacji:
Rozważ użycie interfejsów, jeśli któreś z poniższych stwierdzeń dotyczy Twojej sytuacji:
Źródło
źródło
Odpowiedzi różnią się w zależności od języka. Na przykład w Javie klasa może implementować (dziedziczyć) wiele interfejsów, ale dziedziczyć tylko z jednej klasy abstrakcyjnej. Interfejsy zapewniają większą elastyczność. Ale nie jest to prawdą w C ++.
źródło
Dla mnie w wielu przypadkach korzystałbym z interfejsów. Ale w niektórych przypadkach wolę zajęcia abstrakcyjne.
Klasy w OO zasadniczo odnoszą się do wdrażania. Korzystam z klas abstrakcyjnych, gdy chcę wymusić pewne szczegóły implementacji dla dzieci, w przeciwnym razie korzystam z interfejsów.
Oczywiście klasy abstrakcyjne są przydatne nie tylko w wymuszaniu implementacji, ale także w dzieleniu się pewnymi szczegółowymi szczegółami wśród wielu powiązanych klas.
źródło
Użyj klasy abstrakcyjnej, jeśli chcesz podać podstawowe implementacje.
źródło
w java możesz odziedziczyć po jednej (abstrakcyjnej) klasie, aby „zapewnić” funkcjonalność i możesz zaimplementować wiele interfejsów, aby „zapewnić” funkcjonalność
źródło
Czysto na podstawie dziedziczenia użyłbyś abstraktu, w którym wyraźnie definiujesz potomka, abstrakcyjne relacje (tj. Zwierzę-> kot) i / lub wymaga dziedziczenia właściwości wirtualnych lub niepublicznych, zwłaszcza stanu wspólnego (którego interfejsy nie mogą obsługiwać ).
Powinieneś starać się faworyzować kompozycję (poprzez wstrzykiwanie zależności) nad dziedziczeniem, o ile możesz, i zauważ, że interfejsy będące umowami wspierają testowanie jednostkowe, rozdzielanie problemów i (w zależności od języka) wielokrotne dziedziczenie w sposób, w jaki Abstrakty nie mogą.
źródło
Ciekawym miejscem, w którym interfejsy wypadają lepiej niż klasy abstrakcyjne, jest potrzeba dodania dodatkowej funkcjonalności do grupy (powiązanych lub niepowiązanych) obiektów. Jeśli nie możesz dać im podstawowej klasy abstrakcyjnej (np. Są
sealed
lub mają już element nadrzędny), możesz zamiast tego dać im fikcyjny (pusty) interfejs, a następnie po prostu napisać metody rozszerzenia dla tego interfejsu.źródło
Może to być bardzo trudny telefon ...
Jeden wskaźnik, który mogę podać: Obiekt może implementować wiele interfejsów, podczas gdy obiekt może odziedziczyć tylko jedną klasę bazową (w nowoczesnym języku OO, takim jak c #, wiem, że C ++ ma wielokrotne dziedziczenie - ale czy to nie jest obrzydzone?)
źródło
Klasa abstrakcyjna może mieć implementacje.
Interfejs nie ma implementacji, po prostu definiuje rodzaj umowy.
Mogą występować również różnice zależne od języka: na przykład C # nie ma wielokrotnego dziedziczenia, ale wiele interfejsów można zaimplementować w klasie.
źródło
Podstawowa reguła kciuka: dla „Rzeczowników” użyj klasy Abstrakcja, a dla „Czasowników” użyj interfejsu
Np .:
car
jest klasą abstrakcyjną idrive
możemy zrobić z niej interfejs.źródło
drive
w samochodzie - jest to klasa abstrakcyjna.