2009-11-23 3 views
8

Kushal Paudyal zapytał how deep you can nest inner classes w Javie. Konsensus jest taki, że choć sam język nie nakłada żadnych ograniczeń, system operacyjny i system plików mogą.Czy rozsądnie jest zagnieździć klasy wewnętrzne Java głębiej niż jeden poziom?

Czy kiedykolwiek znalazłeś przypadek, w którym pomocne są dwa lub więcej poziomów zagnieżdżonych klas wewnętrznych?

Aktualizacja (11/28): Jeśli weźmiesz pod uwagę klasy wyliczeniowe, drugi poziom zagnieżdżania może mieć sens. Podczas niedawnego refaktoryzacji krótko miałem zewnętrzną klasę (klient HTTP), wewnętrzną klasę (pamięć podręczną w pamięci), a wewnątrz wewnętrznej klasę enum (dla strategii eksmisji pamięci podręcznej). Wydawało się, że to w porządku, ale do punktu, o którym mówiłem: "Thorbjørn", kontynuowałem, wydobywając klasę pamięci podręcznej i jej wewnętrzne wyliczenie z klasy klienta HTTP.

Odpowiedz

4

Nie. Nie.

Standardowym przykładem klasy wewnątrz klasy jest Builder, w której znajduje się podklasa, która pomaga utworzyć poprawną instancję z wieloma możliwymi metodami konfiguracji.

Osobiście uważam bardziej złożony przypadek klas zagnieżdżonych za doskonały przykład kodu, który wymaga refaktoryzacji.

+0

Zwykle się zgadzam. –

+0

Proszę zauważyć, że nie uważam tego za anonimowe. Są koniecznym bólem, jeśli potrzebujesz "łatwego" dostępu do zmiennych zewnętrznych. Mimo to uważałbym, że anonimowa klasa w innym jest zapachem kodu. –

3

Nie osobiście natknąłem się na przypadek, w którym więcej niż jedna okazała się konieczna. Mógłbym przewidzieć przypadek, w którym dwie mogą okazać się użyteczne. Mam jednak problem z wyobrażeniem sobie więcej niż dwóch.

Przykład, który sobie wyobrażam, znajduje się w kodzie Java GUI. W pewnych okolicznościach może być użyteczne umieszczenie klasy zagnieżdżonej w już zagnieżdżonym ActionListener.

1

Pewnie - jest to czasami ważne. Właśnie kilka minut temu.

Na przykład, w jakimś kodzie testowym, który napisałem, chciałem ustawić kilka elementów, które obsługują uruchamianie wielu kalamburów. Płyta podstawowa była potrzebna do utworzenia wielu wystąpień podpalanego fragmentu kodu. W tym przykładzie tworzę instancję fabryki, która przejdzie do threadedTest, a ta fabryka tworzy nowe kalki.

@Test public void testXXXXXXXX() throws Throwable { 
    threadedTest(new CallableFactory() { 
     @Override public Callable<Request> create() { 
      return new Callable<Request>() { 
       // might have state 
       @Override public Request call() throws Exception { 
        // do the steps for this test 
        return ...; 
       }}; 
     }}); 
} 

O wiele bardziej zwięzła niż tworzenie dwóch nowych klas, w których jedna tworzy drugą. Oczywiście jest tu kara czytelności, dopóki nie przyzwyczaisz się do stylu, ale ...

Jeśli połączysz to z szablonem, aby kontrolować transakcje lub połączenie/zamknięcie bazy danych, może to skończyć się na trzech głębokościach. (Miałem taki kod, jeśli to robisz, pamiętaj, aby napisać próbkę w swoich komentarzach i dobrze wyjaśnić strukturę)

+1

Są to anonimowe klasy wewnętrzne, a nie zagnieżdżone klasy wewnętrzne. Te dwie koncepcje są traktowane inaczej na http://java.sun.com/docs/books/tutorial/java/javaOO/nested.html –

+0

Powyższe mogłyby łatwo zostać zagnieżdżonymi klasami, chociaż nie chciałbym tego napisać sposób;) –

+1

Mogli, ale nie byli. –

2

Jeśli generujesz kod z niektórych danych, zagnieżdżone klasy mogą być dobry sposób na unikanie kolizji nazw.

2

Widziałem użycie liczby poziomów zagnieżdżonych klas.

Istnieje starsza maszyna o nazwie Tandem (HP), która początkowo uruchamia kod COBOL/C. Później pojawiają się "łatki", które umożliwiają również uruchamianie java. Struktura zmiennych języka COBOL jest naturalnie wielopoziomowa (nawet 5 poziomów jest częstym przypadkiem), więc aby umożliwić wywoływanie języka Java do serwerów COBOL, klasy Java były również wielopoziomowe, aby uprościć konwersję danych między nimi. .

Zgadzam się, że jest to bardzo nietypowy przypadek, ale w każdym razie ...

2

wiem, że recykling stary wątek, ale to dla mnie nowe :)

Używamy wielu poziomach dla naszych POJOs dla deserializacji JSON (z Jackson). Oto mały przykład (złożony) od JSON możemy wrócić z relaksującego usługi internetowej:

{ success: true, response: { 
    sales: { item: "123", sales: 3, returns: 1 }, 
    inventory: { item: "567", qty: 100 } 
    } 
} 

Kiedyś mieliśmy POJOs skonfigurowane następująco:

public class Json1 { 
    private boolean success; 
    private JsonResponse response; 
} 
public class Json1Response { 
    private JsonResponseSales sales; 
    private JsonResponseInventory inventory; 
} 
public class Json1ResponseSales { 
    private String item; 
    private int sales; 
    private int returned; 
} 
public class Json1ResponseInventory { 
    private String item; 
    private int qty; 
} 

mamy wiele z tych, z POJO dla każdego żądania usługi sieciowej, które możemy wykonać. Ten układ dał nam kilka nurtujących wątpliwości:

  1. Zauważ, że ten jeden, względnie prosty przykład dał nam cztery pliki klas, aby nadążyć za. Teraz pomnóż to przez 100, a następnie "współczynnik trudności" równy 3, aby uwzględnić fakt, że większość JSON jest dużo bardziej nieprzyjemna. Tysiące plików.

  2. Nazwy pól są ponownie używane w całym miejscu, a ta sama nazwa pola może mieć różną zawartość w zależności od usługi internetowej. (Wyobraź sobie, że ilości może wrócić jako ciągi z jednego serwisu WWW, int od drugiego, a następnie pomnożyć przez 100s.)

Ponieważ te rzeczy są ze sobą powiązane w relacji rodzic/dziecko, zdecydowaliśmy się iść z ten układ zamiast.

public class Json1 { 
    private boolean success; 
    private JsonResponse response; 

    public class Json1Response { 
    private JsonResponseSales sales; 
    private JsonResponseInventory inventory; 

    public class Json1ResponseSales { 
     private String item; 
     private int sales; 
     private int returned; 
    } 

    public class Json1ResponseInventory { 
     private String item; 
     private int qty; 
    } 
    } 
} 

W tym przypadku, jestem głęboko zagnieżdżone dwa, ale może być ich więcej. Może do czterech głębokości.