Co to jest kod „zazdrości funkcji” i dlaczego uważa się go za zapach kodu?

53

To pytanie na temat SO mówi o poprawieniu tego, co według OP jest kodem zazdrości funkcji . Innym przykładem, w którym widziałem cytowanie tej fajnej frazy, jest ostatnio udzielona odpowiedź tutaj w programmers.SE. Chociaż dodałem komentarz do tej odpowiedzi, prosząc o informacje, które - jak sądzę - byłyby przydatne dla programistów po pytaniach i odpowiedziach, aby zrozumieć, co oznacza termin „zazdrość o funkcje” . W razie potrzeby edytuj dodatkowe tagi.

Maniak
źródło

Odpowiedzi:

88

Zazdrość o cechy to termin używany do opisania sytuacji, w której jeden obiekt trafia na pola innego obiektu w celu wykonania jakiegoś obliczenia lub podjęcia decyzji, zamiast prosić obiekt o wykonanie obliczeń.

Jako trywialny przykład rozważ klasę reprezentującą prostokąt. Użytkownik prostokąta może potrzebować znać jego obszar. Programista może ujawnić widthi heightwypełnić pola, a następnie wykonać obliczenia poza Rectangleklasą. Ewentualnie Rectanglemógłby zachować widthi heightpól prywatnych i zapewnić getAreametodę. Jest to prawdopodobnie lepsze podejście.

Problem z pierwszą sytuacją i powodem, dla którego jest uważany za zapach kodu, jest taki, że przerywa on enkapsulację.

Zasadniczo, za każdym razem, gdy często korzystasz z pól innej klasy do wykonywania dowolnej logiki lub obliczeń, rozważ przeniesienie tej logiki do metody w samej klasie.

jhewlett
źródło
7
+1, chociaż twój przykład nie jest realistyczny, ponieważ przydatna klasa Rectangle zazwyczaj ujawnia również pola szerokości i wysokości.
Doc Brown,
2
I chociaż złamanie enkapsulacji może nastąpić razem z „Envirismem cech”, w większości rzeczywistych przykładów, jakie do tej pory widziałem, prawdopodobnie tak nie było. Zdarza się to bardziej w sytuacjach „hej, muszę obliczyć niektóre rzeczy tylko w kodzie przy użyciu tego obiektu i nie jestem pewien, czy mogę dotknąć implementacji tego obiektu / czy powinniśmy powierzyć temu obiektowi odpowiedzialność za to obliczenie”. Następnie wykonuje się obliczenia za pomocą pól, które są już odkryte (chociaż prawdopodobnie znacznie czystsza implementacja byłaby możliwa w obrębie obiektu).
Doc Brown
2
@DocBrown Wyobraź sobie prostokąt narysowany na powierzchni torusa, stożka lub kuli. Jeśli moja biblioteka rysowania kształtów tworzy obiekty, które są w stanie uzyskać prawidłowe wyniki w takich kontekstach, głupotą byłoby nie pozostawić ich do obliczenia własnych obszarów - w dowolnym kontekście.
itsbruce
1
@OskarN .: definicji mówimy o funkcji, które potrzebne. Są oczywiście potrzebne, jeśli inne klasy ponownie je wdrażają.
Aaronaught
1
@OskarN .: to zależy; czasami decyzja jest jasna, czasem kwestia gustu, a najczęściej kwestia doświadczenia. W twoim artykule istnieją dobre powody, dla których Scott Meyers pisze „ czasami mniej znaczy więcej” i że zajęło mu lata, aby zrozumieć, kiedy nie zastosować swojego „algorytmu do decydowania, kiedy należy wprowadzić funkcję członka”.
Doc Brown
1

Może się zdarzyć, że użycie innych metod klasy / struct będzie w porządku - gdy twoja klasa / struktura jest pojemnikiem na dane. Zwykle niewiele można zrobić z tymi danymi bez kontekstu zewnętrznego.

Takie klasy mogą nadal zawierać pewną wewnętrzną logikę, ale częściej są używane jako kontenery:

class YourUid {
 public:
  YourUid(int id_in_workplace_, int id_in_living_place_, DB* FBI_database, int id_in_FBI_database);
  bool IsInvalidWorker() const { return id_in_workplace == consts::invalid_id_in_workplace; }
  bool CanMessWith() const { return !FBI_database_.is_cool(id_in_FBI_database_); }
  int id_in_workplace;
  int id_in_living_place;
 private:
  int id_in_FBI_database_;
  const DB* FBI_database_;
};

@jhewlett w swojej odpowiedzi odwołuje się do tego artykułu, aby udowodnić, że nie powinieneś intensywnie wykorzystywać innych członków klasy, ale istnieje inny kod pachnący sytuacją opisaną tam z rzecznikami mojego przykładu:

Długa lista parametrów. Ogranicz liczbę parametrów potrzebnych w danej metodzie lub użyj obiektu, aby połączyć parametry.

Ryga
źródło
1
Jak to odpowiada na zadane pytanie?
komar
@gnat Pytanie dotyczy tego, dlaczego uważa się go za „zapach kodu”. jhewlett daje literę A ze zbyt ogólnymi założeniami zakwestionowanymi w komentarzach. Moja odpowiedź to 2 centy, aby odróżnić „zapach kodu” od normalnej praktyki.
Ryga