Czy interfejs może zależeć od konkretnych klas?

9

Tworzę interfejs w Javie dla niestandardowej procedury obsługi błędów.

Chcę przekazać obiekt błędu argumentu, ale potrzebuję go, aby był dzieckiem Exceptionklasy.

Czy mogę używać mojej zdefiniowanej nazwy klasy w interfejsie?

Czy nie zmniejszy to interfejsu, ponieważ nie będzie zależny od żadnej implementacji?

Próbuję zrobić coś takiego:

public class CustomException {
    /* ... Implementation ... */
}

public interface Interface {

    void onError(CustomException ex);

}
nikachx
źródło
Czy próbujesz zapytać, czy dziedziczenie innej klasy w interfejsie jest w porządku?
Snoop,
@StevieV Nie. Zredagowałem pytanie, spójrz.
nikachx
1
@AndresF. To tylko przykład i można go zastosować w dowolnym języku OO dotyczącym używania klas w interfejsach.
nikachx
3
Powiedz mi: czy jest CustomExceptionczęścią implementacji czy częścią interfejsu?
user253751
2
@nikix Nie rozumiem, co rozumiesz przez „bezpieczny”. W jaki sposób jest Stringbezpieczniejszy niż CustomException? Dlaczego ma to znaczenie, jeśli CustomExceptionz kolei ma inne zależności?
Andres F.

Odpowiedzi:

2

Najpierw muszę zwrócić uwagę na fakt, że CustomExceptionto się nie rozszerza, Exceptionwięc tak naprawdę nie jest Exception.

To mówi:

Jeśli nie zależy ci na zasadzie odwrócenia zależności , pozostaw ją taką, jaka jest. Jest całkowicie OK, aby interfejs zależał od konkretnych klas, na przykład wiele interfejsów zależy od Stringlub Objectktóre są klasami konkretnymi . Chodzi o to, że wierzymy, że klasy należące do Java SDK są bardziej stabilne (mniej podatne na zmiany w łamaniu kodu) niż te, które piszemy.

W drugiej ręce:

Jeśli chcesz postępować zgodnie z DIP (który ma niezliczone korzyści i jest moją rekomendacją), musisz zrobić jedną z dwóch rzeczy:

opcja 1

  • Zrób CustomExceptionstreszczenie
  • Zachowaj void onError(CustomException ex)jak jest

Opcja 2

  • Zrób CustomExceptioninterfejs
  • Zachowaj void onError(CustomException ex)jak jest

Z każdą z tych opcji będziesz zgodny z DIP, ponieważ interfejs nie będzie zależał od żadnej konkretnej klasy, tylko od abstrakcji.

W bezpośrednim zastosowaniu inwersji zależności, abstrakty są własnością warstw wyższych / zasad. Ta architektura grupuje komponenty wyższe / strategiczne i streszczenia, które definiują niższe usługi razem w tym samym pakiecie. Warstwy niższego poziomu są tworzone przez dziedziczenie / implementację tych abstrakcyjnych klas lub interfejsów . Martin, Robert C. (2003).

  • Zwinne tworzenie oprogramowania, zasady, wzorce i praktyki. Prentice Hall. s. 127–131. ISBN 978-0135974445.
Tulains Córdova
źródło
1
Nie ma dużej różnicy między zaakceptowaniem klasy abstrakcyjnej lub konkretnej (nie-końcowej), a różnica w interfejsie to niewiele więcej. Tak długo, jak instancja jest przekazywana jako parametr i nie jest zakodowana na stałe w swojej implementacji, masz podstawy dla DI.
Jacob Raihle
@JacobRaihle Co rozumiesz przez przekazanie instancji zakodowanej na stałe w implementacji?
Tulains Córdova
Powiedziałem „tak długo, jak to jest przekazywane i nie zakodowane na stałe”. Chodzi mi o to, że ponieważ Interfaceinterfejs akceptuje a CustomExceptioni pozostawia programowi wywołującemu zapewnienie go, osoba dzwoniąca może udostępnić dowolną klasę, która rozciąga się, CustomExceptionnawet jeśli CustomExceptionjest to konkretna klasa - co nie byłoby możliwe, gdyby Interfacebył w jakiś sposób odpowiedzialny za tworzenie to. To odwrócenie kontroli, bardziej niż praca z interfejsami (choć to z pewnością pomaga), jest tym, o czym myślę, że w tym wszystkim chodzi.
Jacob Raihle
@JacobRaihle "W bezpośrednim zastosowaniu inwersji zależności, abstrakty są własnością warstw wyższych / strategii. Ta architektura grupuje komponenty wyższych / strategii i abstrakty, które definiują usługi niższe razem w tym samym pakiecie. Tworzone są warstwy niższego poziomu przez dziedziczenie / implementację tych abstrakcyjnych klas lub interfejsów . ” Martin, Robert C. (2003). Zwinne tworzenie oprogramowania, zasady, wzorce i praktyki. Prentice Hall. s. 127–131. ISBN 978-0135974445.
Tulains Córdova
Jaki jest sens klasy abstrakcyjnej, jeśli można podać rozsądną wartość domyślną? Co tracisz , zapewniając to? Myśl nie tylko o cytowaniu książek.
Jacob Raihle,
2

Tulains ma rację - interfejsy cały czas zależą od konkretnych klas. Mają jedynie na celu zawarcie umowy na własne potrzeby. Umowa ta może obejmować pobieranie i zwracanie wszelkiego rodzaju danych.

Pamiętaj, że w językach wyższego poziomu nawet prymitywne typy nie są tak prymitywne. W każdym razie pracujesz z konkretnymi typami!

Sava B.
źródło
0

Myślę, że z nazwy masz na myśli samą klasę. Jeśli próbujesz podać rzeczywistą nazwę klasy wyjątku , aby zainicjować odpowiedni wyjątek za pomocą Reflection, nie jest to właściwa droga.

Jeśli chcesz użyć niestandardowej klasy w interfejsie, możesz oczywiście używać własnych klas we własnych interfejsach. Klasy stają się częścią publicznego interfejsu twojej biblioteki / API. Struktury danych i wyjątki są dobrym przykładem klas, które są często używane przez interfejsy.

Jeśli musisz użyć różnych wyjątków w zależności od kontekstu, możesz być zainteresowany używaniem ogólnych.

Arseni Mourzenko
źródło
Nie, nie mam na myśli refleksji. Tak, jak wspomniałeś Wyjątki i struktury danych mogą być używane w interfejsach, ponieważ zawierają one tylko dane i nie są platformami ani w inny sposób zależne od innych klas. Dziękuję Ci.
nikachx
2
Odpowiedzi, które zadają pytania OP ... Po prostu zadaj komentarz, a następnie podaj swoją odpowiedź.
Snoop,
1
@StevieV: Pierwszy akapit był bardziej retorycznym pytaniem. I jak pokazuje komentarz PO, faktycznie odpowiedziałem na pytanie PO.
Arseni Mourzenko