Podczas programowania w OOP czasami biblioteka / interfejs udostępnia interfejs, którego nie można zmienić. Nazwijmy ten interfejs J.
Teraz masz obiekt klasy A, który zużywa obiekty implementujące ten interfejs. Wewnątrz Potrzebna jest tylko niewielka część definicji interfejsu. Niektóre klasy obiektów są tworzone przeze mnie podczas projektu (nazwijmy jedną z nich typem D), więc na wdrożenie wszystkiego w interfejsie J. wiąże się narzut
Chcę zaimplementować podzbiór funkcjonalności w interfejsie J, ale moje dotychczasowe rozwiązania mnie nie satysfakcjonują:
- implementowanie każdego aspektu J, a następnie rzucanie „notImplementedExceptions” dezinformuje użytkownika moich obiektów: wydaje się, że moje obiekty typu D są zgodne z interfejsem J, ale nie - i inni odbiorcy moich obiektów (które akceptują obiekty implementujące interfejs J) nie mogę polegać na integralności moich obiektów.
- Implementowanie nowo zdefiniowanego interfejsu zabrania mi używania obiektów, które implementują tylko interfejs J, chociaż interfejs J jest w pełni kompatybilny z moim własnym interfejsem.
- Pozwolenie moim niestandardowym obiektom na implementację interfejsu J spowodowałoby znaczne obciążenie, ponieważ nie potrzebują one całej tej funkcjonalności.
Kiedy mogłem zmienić interfejs J, tworzyłem „superinterfejs” K, który posiadałby ten podzbiór funkcjonalności interfejsu J, i czyniłem interfejs J dziedziczonym z interfejsu K. Ale nie mogę zmienić interfejsu J.
Jakie jest obiektowe rozwiązanie tego problemu? Czy najlepsze rozwiązanie nadal implementuje interfejs „just” J? Czy są sposoby OOP na „nadklasę” interfejsu bez jego zmiany?
źródło
Odpowiedzi:
jeśli nie kontrolujesz interfejsu J, utkniesz.
możesz, dla jasności, wdrożyć własny interfejs subJ i interfejs J oraz użyć subJ we własnym kodzie, aby wyjaśnić, że dodatkowe metody w interfejsie J nie są wymagane, ale nie sądzę, że to naprawdę wiele zyskuje
jeśli to możliwe, całkowicie zaimplementuj cały interfejs J.
jeśli to możliwe, skontaktuj się z właścicielem interfejsu J i poproś go o zmianę w celu lepszego dostosowania do twoich celów
źródło
Istotą wdrożenia interfejsu jest zapewnienie ścisłej umowy między dzwoniącym a odbiorcą, która nigdy się nie zmienia, podczas gdy szczegóły implementacji mogą się różnić.
Wdrażając interfejs J, mówisz światu zewnętrznemu, co możesz zrobić.
Jeśli nie potrzebujesz połowy tego, co robi J, to albo interfejs powinien być naprawdę podzielony, ponieważ nie jest tak mały, jak mógłby być, lub musisz wprowadzić
NotImplementedException
metody i właściwości, których nie potrzebujesz. Nie jest to jednak najlepsze rozwiązanie, ponieważ dezorientuje ludzi w kwestii tego, co może zrobić Twój kod.źródło
Jeśli twoja klasa konsumencka A nie wymaga całego interfejsu J, sugerowałbym utworzenie nowego interfejsu (nazwij go K), który kompleksowo opisuje wszystko, czego wymaga.
Daje to wyraźny sygnał każdemu, kto korzysta z klasy A, co do jego strony umowy. W ten sposób zwiększa się szanse na ponowne użycie. Jeśli ktoś musi dostarczyć obiekt, który implementuje duży i złożony interfejs, aby zrobić coś stosunkowo prostego, prawdopodobnie skończy pisać coś, co klasa A zrobi sama.
Aby umożliwić klasie A korzystanie z obiektów implementujących sam interfejs J, można zapewnić klasę opakowania, która implementuje interfejs K i przekazuje wszelkie odpowiednie wywołania do elementu interfejsu J.
źródło
Chociaż zgadzam się z istniejącymi odpowiedziami, które mówią, że naprawdę musisz albo całkowicie zaimplementować J (z wyjątkami dla niezaimplementowanych metod), albo wcale, możliwe obejście jest następujące:
Należy pamiętać, że jest to dość brzydkie rozwiązanie, ponieważ wymaga opakowania, które akceptuje wiele rzeczy, które są zasadniczo takie same. Ale osiąga następujące wyniki:
Jeśli Twój język OO nie zezwala na anonimowe tworzenie instancji interfejsu, możesz utworzyć fikcyjną implementację interfejsu i utworzyć tę instancję.
źródło
Ile zajmie Ci wdrożenie całego interfejsu?
Jeśli zajmie ci to dużo czasu, oznacza to problem z projektem i radziłbym (tak jak zrobił to przede mną Steven A.), aby skontaktował się z właścicielem i sprawdził, czy można go zmienić w przyszłości.
Czy korzystasz z interfejsu we własnym kodzie, niezależnie od biblioteki interfejsu?
Jak zasugerował Steven A., możesz używać własnego interfejsu, tak jak chcesz widzieć go we własnym kodzie. To przynajmniej utrzymuje twój kod wewnętrzny w czystości. Możesz również wysłać to właścicielowi jako interfejs, którego można się spodziewać. Być może zgadza się z tobą, a może może ci wyjaśnić, dlaczego interfejs nie powinien być podzielony.
Czy twoja implementacja kiedykolwiek potrzebowałaby nieużywanych członków interfejsu?
Jeśli możesz się spodziewać, że nigdy nie zostaną wywołane, ponieważ „nie są obsługiwane”, wolę używać
NotSupportedException
. Daje to wyraźne wskazanie, że nigdy nie będziesz obsługiwał tego interfejsu, zamiast go zaimplementować.źródło
NotSupportedException
niego jasno pokazuje, że nie obsługuje tej metody.NotImplementedException
do kodu produkcyjnego, w którym inaczej napisałbym „DO ZROBIENIA: zaimplementuj to” Niestety nie pojawiają się na liście zadań Visual Studio . Ale w praktyce nie pozostawiam metody niezaimplementowanej dłużej niż dwa dni. Resharper pokazuje również te wyjątki pogrubioną czcionką (przynajmniej w mojej konfiguracji). :)Zaimplementuj to, czego potrzebujesz, i wyrzuć wyjątek NoImplementedException na pozostałe.
To kwestia użytkowania. Jeśli nie korzystasz z interfejsu lub wiesz, że Twój kod nie będzie korzystał z interfejsu, nie inwestuj w to czasu, ponieważ nie musisz inwestować czasu w zbędny kod.
Pracuj nad danym zadaniem i pozostań dobrą drogą dla innych, jeśli chcą skorzystać z interfejsu.
Wiele interfejsów w Javie nie jest w pełni zaimplementowanych.
To podejście Apache do rzeczy: http://commons.apache.org/lang/api-2.4/org/apache/commons/lang/NotImplementedException.html
źródło