Che cos'è un codice di "invidia delle caratteristiche" e perché viene considerato un odore di codice?


53

Questa domanda su SO parla della correzione di ciò che OP pensava fosse un codice di invidia delle caratteristiche . Un altro esempio in cui ho visto citare questa frase elegante è in una risposta data di recente qui in programmers.SE. Anche se ho lasciato un commento a quella risposta chiedendo le informazioni, ho pensato che sarebbe stato di aiuto generale ai programmatori che seguono domande e risposte per capire cosa si intende per "invidia delle funzionalità" . Sentiti libero di modificare tag aggiuntivi se ritieni opportuno.


Risposte:


88

Invidia caratteristica è un termine usato per descrivere una situazione in cui un oggetto arriva ai campi di un altro oggetto per eseguire una sorta di calcolo o prendere una decisione, piuttosto che chiedere all'oggetto di eseguire il calcolo stesso.

Come esempio banale, considera una classe che rappresenta un rettangolo. L'utente del rettangolo potrebbe aver bisogno di conoscere la sua area. Il programmatore potrebbe esporre widthe heightcampi e quindi eseguire il calcolo al di fuori della Rectangleclasse. In alternativa, Rectanglepotrebbe mantenere il widthe heightcampi privati e fornire un getAreametodo. Questo è probabilmente un approccio migliore.

Il problema con la prima situazione, e il motivo per cui è considerato un odore di codice, è perché rompe l'incapsulamento.

Come regola generale, ogni volta che ti ritrovi a fare un ampio uso dei campi di un'altra classe per eseguire qualsiasi tipo di logica o calcolo, considera di spostare quella logica in un metodo sulla classe stessa.


7
+1, anche se il tuo esempio non è realistico, dal momento che una utile classe Rectangle espone in genere anche i campi di larghezza e altezza.
Doc Brown,

2
E sebbene la rottura dell'incapsulamento possa accadere insieme a "Feature envirism", nella maggior parte degli esempi del mondo reale che ho visto finora non è stato probabilmente il caso. Succede di più nelle situazioni "ehi, ho bisogno di calcolare alcune cose solo nel codice usando quell'oggetto, e non sono sicuro di poter toccare l'implementazione di quell'oggetto / se dovremmo dare all'oggetto la responsabilità di quel calcolo". E poi si implementa il calcolo usando campi che sono già esposti (anche se un'implementazione molto più pulita sarebbe probabilmente possibile all'interno dell'oggetto).
Doc Brown,

2
@DocBrown Immagina un rettangolo disegnato sulla superficie di un toro, un cono o una sfera. Se la mia libreria di disegni di forme produce oggetti che sono in grado di produrre i risultati corretti in tali contesti, saresti sciocco a non lasciarli per calcolare le proprie aree, in qualsiasi contesto.
itsbruce,

1
@OskarN .: Per definizione stiamo parlando di funzioni che sono necessarie. Sono ovviamente necessari se altre classi li stanno reimplementando continuamente.
Aaronaught,

1
@OskarN .: dipende; a volte la decisione è chiara, a volte è una questione di gusti, e molto spesso è una questione di esperienza. Nel tuo articolo, ci sono buone ragioni per cui Scott Meyers scrive "a volte less is more" e che gli ci sono voluti anni per capire quando non applicare il suo "algoritmo per decidere quando far funzionare i membri della fa".
Doc Brown,

1

Esiste una possibile situazione quando è OK utilizzare ampiamente altri metodi class / struct - quando class / struct è un contenitore per i dati. Di solito c'è poco da fare con questi dati senza contesto esterno.

Tali classi possono ancora contenere una certa logica interna ma più spesso vengono utilizzate come contenitori:

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 nella sua risposta si riferisce a questo articolo per dimostrare che non dovresti usare ampiamente altri membri della classe, ma c'è un'altra situazione di odori di codice descritta lì con i miei sostenitori del mio esempio:

Elenco di parametri lunghi. Limitare il numero di parametri necessari in un determinato metodo o utilizzare un oggetto per combinare i parametri.


1
come risponde alla domanda posta?
moscerino

@gnat Il Q riguarda il motivo per cui è considerato "odore di codice". jhewlett dà una A con alcune ipotesi troppo generali messe in discussione nei commenti. La mia risposta è di 2 centesimi per distinguere "odore di codice" dalla pratica normale.
Riga,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.