Dlaczego CharSequence nie definiuje zawiera (CharSequence)?

11

Dotyczy to zarówno Java SE, jak i Androida, ponieważ umowy są identyczne.

CharSequencenie definiuje contains(CharSequence)metody. Wydaje mi się, że nie mogę znaleźć przyczyny, a włączenie tego byłoby całkiem przydatne, zapobiegając potrzebie dzwonienia w CharSequence#toString()celu sprawdzenia sekwencji znaków.

Na przykład w Androidzie użytkownicy są zmuszeni zadzwonić, Editable#toString()aby sprawdzić, czy zawiera sekwencję znaków, choć Editableimplementuje CharSequence, których można uniknąć, jeśli zostaną CharSequencezdefiniowane contains(CharSequence).

Jaki jest pomysł na wybór tego projektu? Czy jest to potencjalny nadzór, czy może ma to uzasadnienie projektowe?

Vince Emigh
źródło

Odpowiedzi:

10

Chodzi o CharSequenceto, aby zapewnić widok tylko do odczytu sekwencji znaków i to wszystko. Ten interfejs nie zapewnia żadnych manipulacji ciągiem ani metod wyszukiwania. Te są poza zakresem.

Zasada segregacji interfejsu sugeruje, że klienci danego typu nie powinni polegać na metodach, których nie używają. Dlatego interfejs powinien deklarować tylko minimalny użyteczny zestaw. Jeśli inny przypadek użycia wymaga różnych metod, powinien istnieć inny interfejs.

Klient, który potrzebuje tylko źródła znaków, prawdopodobnie nie potrzebuje metod wyszukiwania.

Oczywiście można przesadzić z tą zasadą i uzyskać tysiące małych interfejsów. To też nie jest dobre. Więc CharSequenceinterfejs nie tylko zawierać minimalną charAt()i length()metody, ale również głęboko powiązane metody ogólnospożywczy subSequence(). (CharSequence może zapewnić widok podsekwencji bez kopii ciągu, dlatego powinna to być metoda instancji). Podanie toString()jest prawidłowe, ponieważ metoda i tak zostałaby odziedziczona Object. Metody chars()i codePoints()adaptacja CharSequencedo Streaminterfejsu. Ponieważ są to metody domyślne, nie nakładają one dodatkowych wymagań na implementację klas CharSequence.

Ten CharSequencetyp jest przydatny, gdy metoda potrzebuje ogólnego źródła znaków bez określania konkretnej implementacji (np. String vs. CharBuffer vs. StringBuilder). String#join()I String#contains()metody są dobre przykłady zastosowania CharSequences.

CharSequencePodanie contains()metody nie jest konieczne, ponieważ można ją wdrożyć zewnętrznie. Podczas gdy Java nie ma dogodności w zakresie metod rozszerzenia C #, metoda statyczna jest zasadniczo taka sama. Więc zamiast boolean Editable#contains(CharSequence needle)ciebie miałbyś static boolean contains(CharSequence haystack, CharSequence needle). Algorytmy wyszukiwania ciągów to dobrze zbadany temat informatyki. Różne algorytmy z różnymi kompromisami są łatwo dostępne.

Dalsza lektura:

amon
źródło
2
Możesz wspomnieć „ Interfejs ten nie przewiduje żadnych manipulacji ciąg lub metod wyszukiwania. Są to poza zakresem. ”, Ale containsnie jest to metoda mutacja, i nie ma metody przeszukiwanie istnieje ( charAt), tak jak to się ma ?. Ponadto „ Ponieważ są to metody domyślne, nie nakładają dodatkowych wymagań na klasy implementujące CharSequence. ” - Czy nie containsmożna zaimplementować domyślnie za pośrednictwem impl return to String().contains(...), usuwając wymóg implementacji klas?
Vince Emigh,
1
@VinceEmigh Tak, contains()może być domyślną metodą. Jeśli istniał, nie powinien być implementowany w kategoriach, String#containsale na odwrót: String powinien korzystać z implementacji CharSequence. charAt()Jest inna. Nie implementuje algorytmu wyszukiwania, jest to kluczowa część CharSequence: bez niego zawartość nie mogłaby zostać skopiowana do innego typu String. Strumienie są kluczową częścią Java8, a dodanie tych domyślnych metod jest zgodne z dodatkami do innych interfejsów, takich jak Collection.
amon