Odbyłem krótką debatę ze współpracownikiem. Mówiąc najprościej, czy istnieje dobry powód, aby ukrywać / enkapsulować funkcje, które są czyste?
Przez „czysty” rozumiem definicję wikipedii :
- Zawsze zwraca te same wyniki z tego samego wejścia. (Ze względu na tę dyskusję
Foo Create(){ return new Foo(); }
uważa się ją za nieczystą, jeśliFoo
nie ma semantyki wartości.) - Nie używa stanu zmiennego (oprócz zmiennych lokalnych) ani I / O.
- Nie powoduje skutków ubocznych.
design
pure-function
Telastyn
źródło
źródło
Odpowiedzi:
Czysta funkcja może nadal stanowić szczegół implementacji. Chociaż funkcja może nie wyrządzić szkody (z punktu widzenia nie zerwania ważnych niezmienników / umów), narażając ją zarówno autor, jak i użytkownicy tej klasy / modułu / pakietu tracą. Autor przegrywa, ponieważ teraz nie może go usunąć, nawet jeśli implementacja ulegnie zmianie, a funkcja nie będzie mu już przydatna. Użytkownicy przegrywają, ponieważ muszą je przejrzeć i zignorować dodatkowe funkcje, które nie są istotne dla używania interfejsu API, aby go zrozumieć.
źródło
Pytanie jest odwrócone.
Nie szukasz powodu, aby funkcja była niepubliczna. Na początek jest to niewłaściwy sposób myślenia (moim zdaniem). Rozumowanie powinno pójść w drugą stronę.
Innymi słowy - nie pytaj „dlaczego miałbym to uczynić prywatnym?”. Zapytaj: „dlaczego miałbym to upublicznić?”
W razie wątpliwości nie ujawniaj tego. To trochę jak brzytwa Ockhama - nie rozmnażaj się, ponieważ jest to konieczne.
EDYCJA: Reagowanie na kontrargumenty poruszone przez @Telastyn w komentarzach (aby uniknąć tam długiej dyskusji):
Tak, czasem jest to bolesne, jeśli klasa jest otwarta na dziedziczenie, ale nie można przesłonić niektórych metod prywatnych (których zachowanie chciałbyś zmienić).
Ale
protected
by wystarczyło - i nadal jest niepubliczne.Jeśli stanie się problematyczny, po prostu upublicznij go! Jest konieczność, o której mówiłem :)
Chodzi mi o to, że nie powinieneś tego robić na wszelki wypadek (YAGNI i wszystko).
Pamiętaj, że zawsze łatwiej jest upublicznić funkcję prywatną niż cofnąć ją do prywatności. Ten ostatni prawdopodobnie złamie istniejący kod.
źródło
Nie sądzę, aby decyzja o ukryciu / zamknięciu funkcji mogła zależeć od jej czystości. To, że funkcja jest czysta, nie oznacza, że zewnętrzni muszą o niej wiedzieć. Co ciekawe, jeśli funkcja jest czysta i ma być publiczna, może wcale nie musi być członkiem instancji interfejsu, może lepiej nadaje się jako statyczna. Ale znowu wszystko to zależy od intencji umowy iw tym przypadku logicznego grupowania funkcjonalności, a nie czystości funkcji.
źródło
Klasy powinny być zgodne z zasadą jednolitej odpowiedzialności . Chociaż klasa może potrzebować wezwać inną funkcjonalność, aby osiągnąć swoje cele, powinna ujawniać tylko funkcje, które są częścią jej pojedynczej odpowiedzialności.
Oto tylko jeden przykład przypadku, w którym widoczność może powodować problemy.
Rozważ klasę, która łączy widżety. Być może jako część kodu frobnication potrzebuje jakiejś funkcji narzędzia, która analizuje ciąg znaków: być może musi przekształcić nazwę widżetu w sposób, który nie obsługuje standardowych funkcji łańcucha.
Ponieważ jest to funkcja czysta (łańcuch przychodzi, jakoś go przekształca, zwraca nowy łańcuch), może być publiczny lub prywatny bez konsekwencji. A może to?
Jeśli podasz to do wiadomości publicznej, teraz twoja klasa ma dwa obowiązki: tworzenie widżetów i przekształcanie łańcuchów. Narusza to SRP i może powodować problemy, jeśli inne klasy polegają na tej funkcji. Ponieważ jest to coś, co Twoim zdaniem jest używane tylko wewnątrz klasy, być może zmienisz jej interfejs lub widoczność. Teraz klasy w innych częściach systemu są zepsute.
Zachowując prywatność tej funkcji, nikt nigdy nie ma możliwości polegania na kodzie, który nie jest częścią jednej klasy.
źródło
StringTransformer
klasy do enkapsulacji dwóch lub trzech wierszy kodu, które są używane tylko w jednym miejscu? Zgadzam się, że po użyciu kodu w wielu miejscach najlepiej jest podzielić go na nową klasę z jedną odpowiedzialnością, ale istnieje kompromis.