Znam składnię, reguły zastosowane do klasy abstrakcyjnej i chcę znać użycie klasy abstrakcyjnej
Klasy abstrakcyjnej nie można utworzyć bezpośrednio, ale można ją rozszerzyć o inną klasę
Jaka jest z tego korzyść?
Czym różni się od interfejsu?
Wiem, że jedna klasa może implementować wiele interfejsów, ale może rozszerzyć tylko jedną klasę abstrakcyjną. Czy to tylko różnica między interfejsem a klasą abstrakcyjną?
Mam świadomość korzystania z interfejsu. Nauczyłem się tego z modelu delegowania zdarzeń AWT w Javie.
W jakich sytuacjach powinienem zadeklarować klasę jako klasę abstrakcyjną? Jakie są z tego korzyści?
java
object-oriented
abstract-class
Vaibhav Jani
źródło
źródło
Odpowiedzi:
Ta odpowiedź dobrze wyjaśnia różnice między klasą abstrakcyjną a interfejsem, ale nie odpowiada, dlaczego należy ją zadeklarować.
Z czysto technicznego punktu widzenia nigdy nie ma wymogu deklarowania klasy jako abstrakcyjnej.
Rozważ następujące trzy klasy:
Nie musisz robić abstrakcji klasy Database, nawet jeśli istnieje oczywisty problem z jej implementacją: kiedy piszesz ten program, możesz pisać
new Database()
i będzie poprawny, ale nigdy nie zadziała.Niezależnie od tego nadal zachorowałbyś na polimorfizm, więc dopóki twój program tworzy
SqlDatabase
iOracleDatabase
instancje, możesz pisać metody takie jak:Klasy abstrakcyjne poprawiają sytuację, uniemożliwiając programistom tworzenie instancji klasy podstawowej, ponieważ programista zaznaczył, że brakuje jej funkcjonalności . Zapewnia również bezpieczeństwo podczas kompilacji, dzięki czemu możesz zapewnić, że wszystkie klasy, które rozszerzają klasę abstrakcyjną, zapewniają absolutną minimalną funkcjonalność do działania, i nie musisz się martwić o wprowadzenie metod pośredniczących (takich jak ta powyżej), które dziedziczą w jakiś sposób aby magicznie wiedzieć, że muszą zastąpić metodę, aby zadziałała.
Interfejsy to zupełnie osobny temat. Interfejs pozwala opisać, jakie operacje można wykonać na obiekcie. Zazwyczaj używasz interfejsów podczas pisania metod, komponentów itp., Które korzystają z usług innych komponentów, obiektów, ale nie obchodzi cię, jaki jest rzeczywisty typ obiektu, z którego otrzymujesz usługi.
Rozważ następującą metodę:
Nie obchodzi cię, czy
database
obiekt dziedziczy po jakimś konkretnym obiekcie, zależy ci tylko na tym, że ma onaddProduct
metodę. W takim przypadku interfejs jest bardziej odpowiedni niż sprawienie, aby wszystkie twoje klasy dziedziczyły po tej samej klasie bazowej.Czasami połączenie tych dwóch działa bardzo dobrze. Na przykład:
Zwróć uwagę, jak niektóre bazy danych dziedziczą po RemoteDatabase, aby dzielić się pewną funkcjonalnością (np. Łączenie się przed zapisaniem wiersza), ale FileDatabase to osobna klasa, która tylko się implementuje
IProductDatabase
.źródło
Podobieństwa
Klasy abstrakcyjne i interfejsy są wymagane do abstrakcji. Nie można ich utworzyć za pomocą nowego , ale można je rozwiązać poprzez odwrócenie kontenerów kontrolnych lub wzorce fabryczne.
Różnica
Interfejsy
Klasa abstrakcyjna
Naprawdę łatwo jest znaleźć odpowiedź za pomocą prostego zapytania Google .
źródło
W klasie abstrakcyjnej możesz zaimplementować niektóre metody i pozostawić (wymusić) resztę implementacji przez klasę rozszerzającą. Nie można zaimplementować metod w interfejsie. Nie możesz zmusić nikogo do zastąpienia czegokolwiek przy rozszerzaniu zwykłej klasy. Dzięki klasie abstrakcyjnej możesz.
źródło
Klasy abstrakcyjne są dla relacji „jest to”, a interfejsy są przeznaczone dla „można zrobić”.
Klasy abstrakcyjne pozwalają dodawać podstawowe zachowania, dzięki czemu programiści nie muszą kodować wszystkiego, a jednocześnie zmuszają ich do podążania za twoim projektem.
źródło
Oprócz głębokich szczegółów technicznych - takich jak implementacja niektórych metod dla klas abstrakcyjnych itp., Znaczenie jest takie:
Interfejsy definiują wspólne możliwości - IEnumerable określa, że klasa, która implementuje ten interfejs, może zostać wyliczona. Nie mówi nic o samej klasie.
Klasy abstrakcyjne (lub podstawowe) definiują zachowanie - WebRequest definiuje wspólne zachowanie wszystkich klas potomnych, takich jak HttpWebRequest itp. Definiuje podstawowe znaczenie klasy i jej prawdziwy cel - dostęp do zasobów sieciowych.
źródło
Wpis w Wikipedii .
Główne różnice między interfejsem a klasą abstrakcyjną polega na tym, że klasa abstrakcyjna może zapewniać zaimplementowane metody. Dzięki interfejsom możesz deklarować tylko metody, pisać ich podpis. Oto przykład klasy, która rozszerza klasę abstrakcyjną, która implementuje dwa interfejsy: (java)
W tym przykładzie MyAbstractClass udostępnia metodę publiczną, która drukuje wszystkie trzy wartości. W ImpClass musisz zaimplementować odpowiednio getValue1 i getValue2 z MyInterface1 i MyInterface2 oraz getValue3 z klasy abstrakcyjnej.
Voilà.
Jest więcej aspektów (interfejs: tylko metody publiczne, klasa abstrakcyjna: chronione streszczenie i publiczne metody abstrakcyjne), ale możesz to przeczytać sam.
Na koniec, klasa abstrakcyjna, która zapewnia jedynie metody abstrakcyjne, jest „czystą” abstrakcyjną klasą bazową, czyli interfejsem.
źródło
Innymi słowy, powinieneś zacząć od pytania: „czy te klasy koniecznie współużytkują implementację , czy tylko mają wspólny interfejs ?”
Jeśli odpowiedź jest mieszana, na przykład - te trzy klasy muszą współużytkować implementację, ale te dwie pozostałe współużytkują tylko interfejs API - możesz stworzyć interfejs dla wszystkich pięciu z nich i klasę abstrakcyjną dla tych trzech ze wspólnym kod.
Istnieją również inne sposoby udostępniania implementacji, na przykład enkapsulowanie obiektu za pomocą tej implementacji (np. We wzorze strategii ).
źródło
Zadeklarujesz streszczenie klasy, jeśli nie chcesz, aby programista (prawdopodobnie sam) mógł go utworzyć, ponieważ to nie działałoby lub nie miałoby sensu.
Rozważmy na przykład grę, w której istnieją różne typy elementów gry. Wszystkie dziedziczą od
GameEntity
klasy podstawowej .Ta klasa jest zadeklarowana,
abstract
ponieważ nie ma sensu jej tworzyć. Deklaruje niektóre akcje dla elementów gry i niektóre atrybuty, ale nigdzie w tej klasie te atrybuty nie są inicjowane. Ta klasa służy jako szablon dla elementów gry, ale nie jest przeznaczona do samodzielnego tworzenia i jako taka deklarowanaabstract
.Jeśli chodzi o różnicę w użyciu między klasą abstrakcyjną a interfejsem:
Moim zdaniem interfejs jest sposobem na uzyskanie zachowania polimorficznego bez ograniczenia przez mechanizm pojedynczego dziedziczenia niektórych języków.
Wróćmy do gry jako przykład. Rozważ klasę
Enemy
pochodnąGameEntity
. Ta klasa ma metodęattackMeFromDistance(RangedAttacker attacker)
. Ta metoda ma na celu umożliwić bytom atakowanie wroga z daleka.Jak widać, ta metoda przyjmuje
RangedAttacker
typ jako parametr. Jednak wszystkie jednostki gry już dziedzicząGameEntity
. Nie mogą przedłużyć kolejnej klasy.Weź udział w zajęciach
Mage
iArcher
na przykład. Chcemy zezwolić, aby oba z nich były akceptowane jako parametry wattackMeFromDistance(RangedAttacker attacker)
metodzie, ale już one pochodząGameEntity
.Aby rozwiązać ten problem, tworzymy nowy interfejs:
Klasa, która implementuje ten interfejs, musi implementować
attackFromDistance()
metodę, dlatego jest zapewnione, że ma ona możliwości ataku dystansowego. Oznacza to, żeattackMeFromDistance
metoda może teraz bezpiecznie akceptować klasy implementujące ten interfejs. Tak więc tworzenieMage
iArcher
implementacja tego interfejsu rozwiązuje nasz problem.Dla mnie jest to siła interfejsów.
Podsumowując, zwykle używasz klasy abstrakcyjnej, gdy chcesz mieć klasę bazową dla niektórych klas, ale nie ma sensu tworzyć jej samodzielnie (lub w przypadku, gdy ma
abstract
metody, które muszą być zaimplementowane przez podklasy, a w tym przypadku kompilator wymusi utworzenie klasyabstract
). Można użyć interfejsu, aby uzyskać zachowanie polimorficzne bez ograniczenia przez mechanizm pojedynczego dziedziczenia.źródło
źródło