Czy klasy zagnieżdżone są niedoceniane?

9

Nie próbuję powiedzieć, że wiem coś, czego wszyscy inni nie wiedzą, ale rozwiązuję coraz więcej projektów za pomocą klas zagnieżdżonych, więc jestem ciekawy, czy mam poczucie akceptowalności korzystania z tego pozornie rzadko używanego mechanizm projektowania.

To prowadzi mnie do pytania: czy schodzę z natury złą drogą z powodów, które odkryję, kiedy wrócą mnie ugryźć, czy też zagnieżdżone klasy mogą być niedoceniane?

Oto dwa przykłady, dla których właśnie ich użyłem: https://gist.github.com/3975581 - pierwszy pomógł mi utrzymać ściśle powiązane ze sobą heirarchiczne rzeczy, drugi dał mi dostęp do chronionych członków dla pracowników ...

Aaron Anodide
źródło
Chcę tylko podziękować za odpowiedzi / spostrzeżenia - nie jestem pewien, jak wybrać odpowiedź, więc zostawiam ją, zastanawiając się nad otrzymaną radą i ponownie odwiedzam ...
Aaron Anodide

Odpowiedzi:

6

Nie nazwałbym tego „rzadko stosowanym mechanizmem projektowania” - przynajmniej nie uniwersalnie: chociaż istnieją sklepy, w których niektórzy współpracownicy mogą się krzywić, używając klas zagnieżdżonych, nie jest to wcale niejasna funkcja.

Chociaż istnienie klas z widocznością zestawu i wprowadzenie lambd znacznie zmniejszyło zapotrzebowanie na klasy zagnieżdżone * , pozostają one ważnym wyborem projektowym. Chociaż w przestrzeni nazw występuje pewne nakładanie się z klasami wewnętrznymi, funkcja klas zagnieżdżonych jest unikalna, ponieważ pozwala ukryć klasę całkowicie w innej klasie.


* Korzystanie z podobnej funkcji w Javie jest znacznie wyższe, ponieważ innych alternatyw dostępnych w języku C # nie ma w Javie.

dasblinkenlight
źródło
Czy dobrze jest ukryć klasę całkowicie w innej klasie zgodnie z istotą projektu OOP?
Maxood,
1
@Maxood Dobrze jest ukryć klasę, jeśli możesz ją ukryć. Użytkownik interfejsu API powinien wiedzieć jak najmniej o sposobie implementacji interfejsu API.
dasblinkenlight
3

Zastanów się przez chwilę, że piszesz klasę w innej klasie, która nigdy nie będzie używana nigdzie indziej w twoim programie. Ponieważ gdybyś używał go gdzie indziej, uczyniłbyś go zwykłą klasą publiczną, tak jak wszystkie inne.

Tak więc nie ma tutaj rzeczy, która ma sprawić, że OOP będzie świetna (wielokrotnego użytku). Poza tym, co można osiągnąć z klasą zagnieżdżoną, czego nie można osiągnąć za pomocą zwykłych metod i członków prywatnych w klasie nadrzędnej?

Aby znaleźć użyteczny wzorzec oprogramowania wykorzystujący zagnieżdżone klasy, spójrz tutaj .

Robert Harvey
źródło
10
Nigdy nie kupiłem tej rzeczy do ponownego użycia, a przynajmniej nie tak, jak to zwykle bywa. (1) Wywoływanie do istniejącego kodu / klas (o których wydajesz się mówić, i które zwykle postrzegam jako definicję ponownego użycia) nie ma absolutnie nic wspólnego z OOP, to po prostu podstawowa modułowość. (2) Polimorfizm podtypu, który jest jedną z charakterystycznych cech OOP, pozwala na ponowne użycie kodu klienta , czyniąc konkretną implementację nieistotną , tj. Działa dokładnie tak samo, niezależnie od tego, czy konkretna klasa jest dostępna, czy nie. IOW to ponowne użycie, które kupuję, ale działa również z klasami zagnieżdżonymi.
1
Powiedziałbym, że istnieje także izolacja przestrzeni nazw podana przez klasę nadrzędną - więc jeśli chcesz, obie klasy A i B mogłyby zagnieżdżać klasę „Params” oraz dostęp do niepublicznych członków klasy zawierającej. Czyż nie są to oba powody, aby mieć klasy wewnętrzne, które są używane poza klasą?
Aaron Anodide
@AaronAnodide To powinna być odpowiedź na dobry sposób korzystania z zagnieżdżonych klas. Dokładnie jak / dlaczego ich używam, pomaga uporządkować kod.
Izkata
2

am I going down an inherintly bad path

Myślę, że w twoim drugim przykładzie (podklasy pracowników) zdecydowanie jesteś. Odwzorowałeś każdą podklasę na określony stan w superklasie. Dlatego teraz za każdym razem, gdy chcesz dodać stan do superklasy, musisz wprowadzić zmiany w trzech lokalizacjach (dodaj stan do superklasy, dodaj nową podklasę i zmień konstruktor klasy pochodnej, aby dodać podklasę do listy ).

Korzystanie z zagnieżdżonych klas w celu uzyskania dostępu do prywatnych członków wydaje się być prawidłowym zastosowaniem (nigdy tego osobiście nie zrobiłem), ale konkretny przypadek tutaj nie działa.

Jeśli chodzi o przykład części ciała. Ponieważ wszystkie zagnieżdżone klasy są publiczne, tak naprawdę niewiele robisz oprócz przestrzeni nazw. Jeśli klasy te powiększą się o większą funkcjonalność, może się okazać, że klasy zagnieżdżone po prostu zaśmiecają interfejsy i przeglądasz kod, aby znaleźć coś konkretnego. Zauważam również, że ponieważ zagnieżdżałeś klasy, jesteś zmuszony złamać konwencje nazewnictwa i nazwać swoje klasy małymi literami (być może to był wybór). Ale te argumenty są bardziej powierzchowne niż cokolwiek, co faktycznie jest złe.

Chyba, że ​​oczywiście musiałeś wdrożyć bezcielesne ramię. Następnie utworzenie ramienia przez wykonanie następujących czynności jest mylące, ponieważ nie ma ciała / tułowia / boku. (Zauważ także mylącą obudowę).

arm newArm = new Body.torso.side.arm("");
nickles80
źródło
1

Jedyną zaletą zagnieżdżonych klas jest to, że można je ustawić jako prywatne (lub chronione). Powiedziałbym, że w tym przypadku klasy zagnieżdżone mogą pomóc w enkapsulacji funkcjonalności, jeśli klasa ma być używana przez klasę zewnętrzną i samą klasę.

Bok McDonagh
źródło
1

Z mojego doświadczenia wynika, że ​​zagnieżdżone klasy

  • Wrócił, by mnie prześladować
  • Były używane, gdy chciałem skracać rogi
  • Testowanie koszmaru
  • Miał negatywny wpływ na rozdzielenie problemów i ogólny projekt

Rzuciłem okiem na twoją klasę i od razu myślę, że:

  • Patrzenie na to jest bolesne, ponieważ klasa jest ogromna
  • Nie mogę przetestować „palców” bez tworzenia całego ciała
  • Nie mogę mieć wielu implementacji tułowia. Nie wydaje się to oczywiste w kontekście „ludzkiego ciała”, ale w innym scenariuszu stanie się to oczywiste.

Dlaczego nie podzielić swojej klasy na wiele klas i nadać im osobne przestrzenie nazw. Na przykład

WindowsGame1.PhysicalModel.UpperBody
WindowsGame1.PhysicalModel.LowerBody
WindowsGame1.PhysicalModel.UpperBody.Arms
CodeART
źródło