Dlaczego najlepiej korzystać z kolekcji pierwszej klasy?

15

Zgodnie z zasadą nr 4 Object Calisthenics autorstwa Jeffa Baya (RTF) w The ThoughtWorks Anthology zaleca się, aby „ używać kolekcji pierwszej klasy ”.

Zasada 4: Kolekcje pierwszej klasy

Stosowanie tej reguły jest proste: każda klasa zawierająca kolekcję nie powinna zawierać innych zmiennych składowych. Każda kolekcja jest pakowana we własną klasę, więc teraz zachowania związane z kolekcją mają swój dom. Może się okazać, że filtry staną się częścią tej nowej klasy. Twoja nowa klasa może również obsługiwać działania, takie jak łączenie dwóch grup razem lub stosowanie reguły do ​​każdego elementu grupy.

Zrozumiałem z tego, że powinniśmy użyć osobnej klasy, która podsumowuje kolekcję i metodami dodawania, usuwania modyfikowania danych tej kolekcji.

i potrzebujemy tego, abyśmy byli pewni, jaki typ danych trafi do kolekcji i co wyjdzie.

Czy w przypadku korzystania z kolekcji ogólnej (w językach, w których ma to zastosowanie), musimy przestrzegać tej zasady?

Jeśli brakuje mi istotnego znaczenia, proszę wyjaśnić.

Amogh Talpallikar
źródło
1
Amogh Talpallikar Zmieniłem regułę 8 na zasadę 4, ponieważ reguła 8 to tak naprawdę „Brak klas z więcej niż dwiema zmiennymi instancji”.
yannis
Wydaje się, że mówi Zasada 8 w spisie treści, a następnie nazwij ją Zasada 4 w treści.
Bezużyteczne
6
Czy to tylko ja, czy też zasada ta jest niemożliwa do wdrożenia, jak napisano? Mam na myśli klasę z kolekcją, więc wyjmujesz wszystko inne. Teraz twoja klasa jest kolekcją. Więc jeśli masz inną klasę, w której jest ta klasa, ma w niej kolekcję i ... pienienie, spłucz, powtórz.
mjfgates,
@mjfgates: hmm ... Świetny punkt! coś, o czym naprawdę warto pomyśleć!
Amogh Talpallikar

Odpowiedzi:

12

Bezpieczeństwo typu to bardzo niewielki powód do korzystania z kolekcji pierwszej klasy. Z Twojego linku:

Reguła 4: Kolekcje pierwszej klasy Zastosowanie tej reguły jest proste: każda klasa zawierająca kolekcję nie powinna zawierać innych zmiennych składowych. Każda kolekcja jest pakowana we własną klasę, więc teraz zachowania związane z kolekcją mają swój dom. Może się okazać, że filtry staną się częścią tej nowej klasy. Twoja nowa klasa może również obsługiwać działania, takie jak łączenie dwóch grup razem lub stosowanie reguły do ​​każdego elementu grupy.

Chodzi o to, że jeśli szukasz, filtrujesz, sprawdzasz poprawność lub cokolwiek poza dodawaniem / usuwaniem / iterowaniem semantyki w kolekcji, kod prosi o umieszczenie jej w swojej klasie. Jeśli musisz zaktualizować tylko jedną wartość (po wyszukiwaniu), prawdopodobnie trafia ona do klasy kolekcji.

Przyczyna tego jest dość prosta, kolekcje są zwykle przekazywane. Wkrótce 4 różne klasy mają własne SearchByID()metody. Lub otrzymujesz zwracane wartości, takie jak Map<Integer, String>w przypadku kontekstu zawartości przechowywanej na tej mapie. Kolekcja pierwszej klasy to proste rozwiązanie, które kosztuje pojedynczy plik źródłowy. W praktyce, gdy już zostaną wprowadzone (bardzo łatwo jest też napisać testy jednostkowe), każda zmiana dotycząca kolekcji jest łatwa do opanowania, na przykład kiedy SearchByIDtrzeba wziąć GUID zamiast int.

Steve Jackson
źródło
8

... użyj osobnej klasy zamykającej kolekcję i metodami dodawania, usuwania modyfikowania danych tej kolekcji

To nie tylko gwarantuje typ obiektów przechowywanych w kolekcjach, ale także gwarantuje niezmienniki kolekcji.

Drzewa (czerwono-czarne, AVL itp.) Są wrażliwe na porządkowanie, a ich zachowanie zależy od ponownego zrównoważenia, gdy jest to właściwe. Wydajność tabeli mieszania będzie również zależeć od odpowiedniego ponownego mieszania. Czy chcesz pamiętać, aby sprawdzać współczynnik obciążenia za każdym razem, gdy wstawiasz mapę haszowania?

FWIW, tekst jest dość jasny na ten temat (i przeredaguję wszystko do twojego pytania, więc nikt inny nie musi pobierać tego RTF):

Każda kolekcja jest pakowana we własną klasę, więc teraz zachowania związane z kolekcją mają swój dom

Nie ma nic wspólnego z typami (a więc i rodzajami), wszystko, co wiąże się z powiązaniem zachowania kolekcji z jej danymi.

Nieprzydatny
źródło
1

Prosta odpowiedź brzmi „Nie”, jeśli używasz języka, który obsługuje Generics. Ponieważ nie ma potrzeby sprawdzania typu, ponieważ sama funkcja języka robi w tym całkiem niezłą robotę (z mojego doświadczenia w języku Java).

Ale jeśli masz dowolną sytuację, w której chcesz dostosować strukturę danych podaną z języka, możesz utworzyć klasę opakowania wokół oryginalnej struktury danych i ujawnić własne interfejsy API i nadal korzystać z podstawowej implementacji oryginalnej struktury danych.

java_mouse
źródło
Myślę również w podobnych liniach. ale powinno być coś, przykłady, które widziałem, były w Javie i C # i oba obsługują kolekcje ogólne.
Amogh Talpallikar
@AmoghTalpallikar: Moim celem było uproszczenie. O ile nie będę musiał nadpisywać żadnego konkretnego zachowania struktury danych, nie będę dostosowywać.
java_mouse