Jeszcze wiele lat dzieli mnie od pełnego zrozumienia różnicy między klasą abstrakcyjną a interfejsem. Za każdym razem, gdy myślę, że rozumiem podstawowe pojęcia, szukam wymiany stosów i mam dwa kroki do tyłu. Ale kilka przemyśleń na ten temat i pytanie PO:
Pierwszy:
Istnieją dwa popularne wyjaśnienia interfejsu:
Interfejs to lista metod i właściwości, które może zaimplementować dowolna klasa, a poprzez implementację interfejsu klasa gwarantuje, że te metody (i ich podpisy) oraz te właściwości (i ich typy) będą dostępne, gdy będą „współpracować” z tą klasą lub obiekt tej klasy. Interfejs to umowa.
Interfejsy to abstrakcyjne klasy, które nic nie mogą / nie mogą zrobić. Są przydatne, ponieważ można zaimplementować więcej niż jedną, w przeciwieństwie do tych średnich klas nadrzędnych. Na przykład mógłbym być obiektem klasy BananaBread i dziedziczyć z BaseBread, ale to nie znaczy, że nie mogę również implementować zarówno interfejsów IWithNuts, jak i ITastesYummy. Mógłbym nawet wdrożyć interfejs IDoesTheDishes, bo nie jestem tylko chlebem, wiesz?
Istnieją dwa popularne wyjaśnienia klasy abstrakcyjnej:
Abstrakcyjna klasa, yknow The coś nie coś, co można zrobić. To tak naprawdę esencja, wcale nie jest prawdziwa. Poczekaj, to pomoże. Łódź to klasa abstrakcyjna, ale seksowny jacht Playboy byłby podklasą BaseBoat.
Czytam książkę o klasach abstrakcyjnych i być może powinieneś ją przeczytać, ponieważ prawdopodobnie jej nie rozumiesz i zrobi to źle, jeśli nie przeczytasz tej książki.
Nawiasem mówiąc, książka Citers zawsze wydaje się imponująca, nawet jeśli nadal jestem zdezorientowany.
Druga:
Na SO ktoś zadał prostszą wersję tego pytania, klasyczne: „po co używać interfejsów? Jaka jest różnica? Czego mi brakuje?” W jednej odpowiedzi wykorzystano pilota sił powietrznych jako prosty przykład. Nie całkiem wylądował, ale wywołał kilka świetnych komentarzy, z których jeden wspomniał o interfejsie IFlyable z metodami takimi jak takeOff, pilotEject itp. I to naprawdę kliknęło mnie jako prawdziwy przykład, dlaczego interfejsy są nie tylko przydatne, ale kluczowe. Interfejs sprawia, że obiekt / klasa jest intuicyjna lub przynajmniej daje wrażenie, że jest. Interfejs nie działa na korzyść obiektu ani danych, ale na coś, co wymaga interakcji z tym obiektem. Klasyczny Fruit-> Apple-> Fuji or Shape-> Triangle-> Równoległe przykłady dziedziczenia są doskonałym modelem do taksonomicznego zrozumienia danego obiektu w oparciu o jego potomków. Informuje konsumenta i przetwórców o jego ogólnych cechach, zachowaniach, bez względu na to, czy obiekt jest grupą rzeczy, podłącza system do systemu, jeśli umieścisz go w niewłaściwym miejscu, lub opisuje dane sensoryczne, złącze do określonego magazynu danych lub dane finansowe potrzebne do sporządzenia listy płac.
Określony obiekt Plane może, ale nie musi mieć metody awaryjnego lądowania, ale będę wkurzony, jeśli założę jego awaryjny ląd i jak każdy inny obiekt latający, aby obudzić się w DumbPlane i dowiedzieć się, że programiści poszli z QuickLand ponieważ myśleli, że to wszystko tak samo. Tak jak byłbym sfrustrowany, gdyby każdy producent śrub miał swoją własną interpretację righty tighty lub jeśli mój telewizor nie miał przycisku zwiększania głośności powyżej przycisku zmniejszania głośności.
Klasy abstrakcyjne to model, który określa, co dowolny potomek musi mieć, aby kwalifikować się jako ta klasa. Jeśli nie masz wszystkich cech kaczki, nie ma znaczenia, że masz zaimplementowany interfejs IQuack, twój po prostu dziwny pingwin. Interfejsy to rzeczy, które mają sens, nawet jeśli nie możesz być pewien niczego innego. Jeff Goldblum i Starbuck byli w stanie latać kosmicznymi statkami kosmicznymi, ponieważ interfejs był niezawodnie podobny.
Trzeci:
Zgadzam się z twoim współpracownikiem, ponieważ czasami musisz egzekwować pewne metody na samym początku. Jeśli tworzysz ORM rekordu aktywnego, wymaga on metody zapisu. To nie zależy od podklasy, którą można utworzyć. A jeśli interfejs ICRUD jest na tyle przenośny, że nie może być sprzężony wyłącznie z jedną klasą abstrakcyjną, może zostać zaimplementowany przez inne klasy, aby uczynić je niezawodnymi i intuicyjnymi dla każdego, kto już zna dowolną z klas potomnych tej klasy abstrakcyjnej.
Z drugiej strony wcześniej był świetny przykład, kiedy nie przeskakiwać do wiązania interfejsu z klasą abstrakcyjną, ponieważ nie wszystkie typy list będą (lub powinny) implementować interfejs kolejki. Powiedziałeś, że ten scenariusz zdarza się w połowie czasu, co oznacza, że ty i twój współpracownik jesteście w błędzie w połowie czasu, a zatem najlepszą rzeczą do zrobienia jest kłótnia, debata, rozważenie, a jeśli okażą się słuszne, uznanie i zaakceptowanie połączenia . Ale nie zostań programistą, który postępuje zgodnie z filozofią, nawet jeśli nie jest ona najlepsza dla danego zadania.