OOP: W jakich sytuacjach projekt oparty na klasie jest lepszy niż projekt oparty na interfejsie?


10

Czytałem stronę internetową JDOM .

Dlaczego interfejs API JDOM jest definiowany w kategoriach konkretnych klas, a nie interfejsów?

Jason Hunter podsumowuje argumenty przeciwko interfejsowi API opartemu na interfejsie JDOM:

Dzięki interfejsom wszystko staje się fabryką, elementy muszą być „importowane” do nowych dokumentów, a nie tylko dodawane, nie można zagwarantować takich funkcji, jak długoterminowa serializacja, a lista jest długa.

Zaczęliśmy od interfejsów. Podczas przeglądu przedpremierowego dla niektórych partnerów otrzymaliśmy informację zwrotną, powinniśmy spróbować konkretnych zajęć. Zrobiliśmy to, a projekt był o wiele lepszy.

Jestem początkującym projektantem. Wszystkie porady, o których słyszałem do tej pory, odradzają stosowanie projektowania z konkretnymi klasami.

Może być użycie konkretnych klas są odpowiednie w niektórych miejscach. Czy są jakieś typowe problemy klasowe, dla których stosowanie konkretnych klas w projektowaniu jest w porządku?


Możesz rzucić
NoChance

Możesz także sprawdzić serię „Ogranicz swoje abstrakcje”: ayende.com/blog/153889/…
henginy

„Zrobiliśmy to, a projekt był o wiele lepszy”. - jak było lepiej?
CodeART

Odpowiedzi:


6
  • Dziedziczenie tworzy zależności od implementacji , co może stanowić duży problem związany z utrzymywalnością. Następstwem tego jest to, że możesz bezpiecznie korzystać z dziedziczenia i konkretnych klas w przypadku obiektu do przesyłania danych , który z definicji nie zawiera prawie żadnej implementacji. Możesz także zastosować dziedziczenie konkretnych klas, jeśli chcesz tę zależność. W takiej sytuacji możesz użyć klasy abstrakcyjnej zawierającej typowe metody (zwykle funkcje narzędziowe) na górze hierarchii.
  • Korzystając z konkretnej hierarchii klas, nie zapomnij zastosować zasady substytucji Liskowa .
  • Nie ma problemu z użyciem konkretnych klas dla klientów (tj. Klas, które używają, a nie klas, które są używane).
  • IMHO możesz używać konkretnych klas, dopóki nie będą rzeczy do zmiany. Zasada Otwarta / Zamknięta mówi, abyś używał interfejsów, aby uniknąć sprzężenia, ale w odniesieniu do zasady , że nie będziesz jej potrzebował, możesz rozważyć użycie konkretnych klas do momentu, kiedy będziesz musiał coś zmienić w implementacji. Problem polega na tym, że musiałbyś zmienić każdego klienta swoich klas, gdy coś gdzieś się zmieni. Chociaż masz tylko jedno możliwe narzędzie do zrobienia czegoś, możesz użyć konkretnych klas IMO.

[EDYCJA] Witryna JDOM bierze przykład java.io.File, ale jest to z pewnością projekt oparty na interfejsie, ponieważ można manipulować instancją java.io.File tak, jakby była tylko serializowalna. W tej sytuacji tylko „twórcy” znają konkretną klasę


Istnieją dwie sprzeczne definicje „obiektu wartości”. Twój wydaje się być mniej powszechny, znany również jako „obiekt do przesyłania danych”.
Michael Borgwardt,

@MichaelBorgwardt Thx za zwrócenie na to uwagi, ponieważ nie miałem na myśli tylko „obiektu do przesyłania danych”: edytuję swoją odpowiedź
Matthias Jouan

1
LSP jest ważny dla każdej relacji podtypu, implementacji interfejsu, a także dziedziczenia.

3

Ze strony JDOM:

Jason (Hunter) założył projekt JDOM na początku 2000 roku wraz z Brettem McLaughlinem

Oznacza to, że mniej więcej w czasie wprowadzania Java 1.3. Jeśli chodzi o rozwój Java, nie było nic na drodze do dojrzałości - najbardziej doświadczeni programiści mieli co najwyżej 4 lata korzystania z Java. Nie było szeroko używanych kontenerów IoC, nie było hibernacji. Właśnie zaczynał się Apache Struts.

To wszystko oznacza, że ​​Jason i Brett się po prostu mylili. Wiele osób jeszcze tego nie „zrozumiało”. Jeśli mieli środowiska C ++, cóż, nie potrzebowaliście interfejsów w C ++ (no cóż, byli tam w C ++, ale tak naprawdę ich nie potrzebowaliście, prawda?), Dlaczego do cholery używacie ich w Javie? Jest wiele dobrych powodów, do których inni mogą cię skierować.

Zdecydowanie się mylili

wszystko, co można zrobić za pomocą interfejsów, można wykonać za pomocą podklasy

Java nie pozwala na wielokrotne dziedziczenie klas, ale pozwala na implementację wielu interfejsów. To może zrobić prawdziwą różnicę.


3

Pamiętaj, jeśli chodzi o twoje pytanie, że w rozwoju oprogramowania istnieje kilka sposobów rozwiązania problemu, a jeśli jakiś programista używa innej techniki niż Twoja, nie oznacza to, że rozwiązanie jest złe.

Jednym z takich przypadków są „interfejsy” kontra (podstawowe) „klasy”. Są sytuacje, w których ten sam cel można osiągnąć za pomocą obu technik.

Aby uprościć sprawę, istnieje kilka zastosowań interfejsów, żeby wspomnieć:

  • jeden polega na zaprojektowaniu „umowy” lub „specyfikacji” bez „wdrożenia”
  • inne, aby dodać funkcjonalność do istniejącej , nie nowej klasy lub hierarchii klas
  • komplementarny do poprzedniego, aby umożliwić dostęp współdzielony między różnymi obiektami, technologiami, przykład: Enterprise Beans, CORBA, COM, WebServices
  • naśladować wielokrotne dziedziczenie

Twoje pytanie dotyczy pierwszego punktu.

Jeśli chcesz opracować hierarchię klas, a nie tylko jedną klasę, a kilka klas ma udostępniać określone funkcje, możesz zacząć od klasy podstawowej, nawet jeśli można to zrobić za pomocą interfejsu.

I pozostaw interfejsy dla innych scenariuszy.

Dobrym przykładem są biblioteki widżetów (kontrolek).

Sugeruję, aby spojrzeć na inne języki programowania, w jaki sposób używają interfejsów i klas, takich jak: PHP, Delphi (Object Pascal), C #.

Twoje zdrowie.


1

Reguły projektowania API są naprawdę specyficzne. Nie jestem pewien, czy powinieneś wyciągać wnioski z tego FAQ, jeśli chodzi o sposób projektowania codziennego kodu.

W przypadku zwykłego kodu nadal prawdą jest, że będziesz używać interfejsu lub dziedziczenia klas abstrakcyjnych znacznie częściej niż IMO dziedziczenia waniliowego.

Aby dobrze zrozumieć tę regułę, musisz postawić się nie z punktu widzenia klasy pochodnej w porównaniu do jej nadklasy, ale z punktu widzenia obiektu, który jest zależny od innego obiektu. Prawie zawsze lepiej jest polegać na abstrakcji niż na konkretnej implementacji, ponieważ pozwala ona zaakceptować całą serię różnych klas jako zależności, opierając się na ich umowie, a nie na szczegółach implementacji.

Pierwsze użycie tego jest często w testach jednostkowych - jeśli naprawdę chcesz do jednostki przetestować swoją klasę w całkowitej izolacji, to zrobić przed fałszywymi wdrożeń swoich zależnościach, które różnią się od rzeczywistych wdrożeń, które będą wykorzystywane w produkcji.


0

Zasadniczo potrzebujesz interfejsu dla wszystkiego, co zostanie przekazane jako parametr lub zwrócone, zasadniczo po to, abyś mógł oddzielić klasę od jej zależności.

Więc jeśli szukamy klasy, nigdy nie omijamy normalnych wyjątków. Nie jestem programistą Java, ale z pewnością w innych podobnych językach nie sądzę, że widziałem interfejsy zdefiniowane dla wyjątków.

Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.