Il numero di interfacce cresce spesso quando un oggetto generico viene utilizzato in ambienti diversi. In C # le varianti di IComparable, IEqualityComparer e IComparer consentono l'ordinamento in configurazioni distinte, quindi si potrebbe finire per implementarle tutte, alcune forse più di una volta poiché è possibile implementare le versioni generiche strongmente tipizzate e le versioni non generiche , inoltre puoi implementare più di uno dei generici.
Facciamo uno scenario di esempio, diciamo un webshop in cui è possibile acquistare crediti con cui è possibile acquistare qualcos'altro (i siti di foto d'archivio usano spesso questo schema). Potresti avere una classe "Valuta" e una classe "Crediti" che ereditano dalla stessa base. Valuta ha alcuni sovraccarichi dell'operatore e procedure di confronto che ti permettono di fare calcoli senza preoccuparti della proprietà "Valuta" (aggiungendo sterline ai dollari, ad esempio). I crediti sono più semplici ma hanno altri comportamenti distinti. Volendo essere in grado di confrontarli tra loro, si potrebbe finire per implementare IComparable e IComparable e le altre varianti di interfacce di confronto su entrambi (anche se usano un'implementazione comune sia che si trovi nella classe base o altrove).
Quando si implementa la serializzazione, ISerializable, IDeserializationCallback viene implementato.
Quindi implementando stack undo-redo: viene aggiunto IClonable.
Funzionalità IsDirty: IObservable, INotifyPropertyChanged.
Permettere agli utenti di modificare i valori usando stringhe: IConvertable ...
L'elenco può andare avanti e avanti ...
Nelle lingue moderne vediamo una tendenza diversa che aiuta a separare questi aspetti e li colloca nelle loro classi, al di fuori della classe principale. La classe o l'aspetto esterno viene quindi associato alla classe di destinazione utilizzando l'annotazione (attributi). Spesso è possibile rendere le classi di aspetto esterne più o meno generiche.
L'uso degli attributi (annotazione) è soggetto a riflessione. Uno svantaggio è la perdita di prestazioni (iniziale) minore. Uno svantaggio (spesso emotivo) è che i principi come l'incapsulamento devono essere rilassati.
Ci sono sempre altre soluzioni, ma per ogni soluzione ingegnosa c'è un compromesso o una presa. Ad esempio, l'utilizzo di una soluzione ORM potrebbe richiedere che tutte le proprietà vengano dichiarate virtuali. Le soluzioni di serializzazione potrebbero richiedere costruttori predefiniti sulle tue classi. Se stai utilizzando l'integrazione delle dipendenze potresti finire per implementare 23 interfacce su una singola classe.
Ai miei occhi, 23 interfacce non devono essere cattive per definizione. Potrebbe esserci uno schema ben congegnato, o qualche determinazione di principio come evitare l'uso della riflessione o credenze di incapsulamento estremo.
Ogni volta che si cambia un lavoro o si deve costruire su un'architettura esistente. Il mio consiglio è di familiarizzare prima di tutto, non cercare di refactoring tutto troppo velocemente. Ascolta lo sviluppatore originale (se è ancora lì) e cerca di capire i pensieri e le idee dietro ciò che vedi. Quando fai domande, fallo non per scomposizione, ma per imparare ... Sì, ognuno ha i propri martelli d'oro, ma più martelli puoi raccogliere più facilmente andrai d'accordo con i tuoi colleghi.