Sono piuttosto pragmatico, ma la mia preoccupazione principale qui è che potresti permettere a questo ConfigBlock
di dominare i tuoi progetti di interfaccia in un modo forse peggiore. Quando hai qualcosa di simile:
explicit MyGreatClass(const ConfigBlock& config);
... un'interfaccia più appropriata potrebbe essere così:
MyGreatClass(int foo, float bar, const string& baz);
... anziché limitarsi a selezionare questi campi con foo/bar/baz
su un massiccio ConfigBlock
.
Lazy Interface Design
Sul lato positivo, questo tipo di design semplifica la progettazione di un'interfaccia stabile per il tuo costruttore, ad esempio, dal momento che se hai bisogno di qualcosa di nuovo, puoi caricarlo in un ConfigBlock
(probabilmente senza alcun codice modifiche) e quindi selezionale tutte le nuove cose di cui hai bisogno senza alcun tipo di cambio di interfaccia, solo una modifica all'implementazione di MyGreatClass
.
Quindi è allo stesso tempo un tipo di pro e contro che questo ti libera dalla progettazione di un'interfaccia più attentamente pensata che accetta solo gli input di cui ha effettivamente bisogno. "Dammi solo questo enorme numero di dati, selezionerò quello che mi serve" al contrario di qualcosa di più simile, "Questi precisi parametri sono ciò che questa interfaccia deve funzionare. "
Quindi ci sono sicuramente alcuni professionisti qui, ma potrebbero essere pesantemente superati dai cons.
Accoppiamento
In questo scenario, tutte le classi costruite da un'istanza ConfigBlock
finiscono per avere le loro dipendenze in questo modo:
QuestopuòdiventareunPITA,adesempio,sesidesideratestarel'unitàClass2
inquestodiagrammaseparatamente.PotrebbeesserenecessariosimularesuperficialmentevariConfigBlock
diinputcontenentiicampipertinentiacuiClass2
èinteressatoperpoterlotestareinunavarietàdicondizioni.
Inqualsiasitipodinuovocontesto(chesiauntestunitarioouninteronuovoprogetto),taliclassipossonodiventarepiùdiunpesodariutilizzare,poichéallafinedobbiamosempreportareConfigBlock
perilguidareeconfigurarlodiconseguenza.
Riutilizzabilità/schierabilità/Testability
Inveceseprogettatequesteinterfacceinmodoappropriato,possiamodisaccoppiarledaConfigBlock
efinireconqualcosadelgenere:
Se noti in questo diagramma sopra, tutte le classi diventano indipendenti (i loro accoppiamenti afferenti / uscenti si riducono di 1).
Ciò porta a classi molto più indipendenti (almeno indipendenti da ConfigBlock
) che possono essere molto più facili da (ri) utilizzare / testare in nuovi scenari / progetti.
Ora questo codice Client
finisce per essere quello che deve dipendere da tutto e assemblarlo tutto insieme. Il carico finisce per essere trasferito su questo codice cliente per leggere i campi appropriati da un ConfigBlock
e passarli nelle classi appropriate come parametri. Tuttavia, tale codice client è generalmente progettato in modo restrittivo per un contesto specifico, e il suo potenziale di riutilizzo sarà in genere pari a zero o comunque (potrebbe essere la funzione main
entry point dell'applicazione o qualcosa del genere)
Quindi, dal punto di vista della riusabilità e dei test, può aiutare a rendere queste classi più indipendenti. Dal punto di vista dell'interfaccia per chi usa le classi, può anche aiutare a specificare in modo esplicito quali parametri hanno bisogno invece di un solo ConfigBlock
che modella l'intero universo di campi dati necessari per tutto.
Conclusione
In generale, questo tipo di design orientato alla classe che dipende da un monolite che ha tutto il necessario tende ad avere questo tipo di caratteristiche. La loro applicabilità, schierabilità, riutilizzabilità, testabilità, ecc. Possono essere notevolmente ridotte di conseguenza. Tuttavia possono semplificare il design dell'interfaccia se proviamo a fare un giro positivo. Spetta a te misurare quei pro e contro e decidere se valgono i trade-off. In genere è molto più sicuro sbagliare contro questo tipo di design in cui si sta selezionando da un monolite in classi che sono generalmente destinate a modellare un progetto più generale e ampiamente applicabile.
Ultimo ma non meno importante:
extern CodingBlock MyCodingBlock;
... questo è potenzialmente anche peggiore (più distorto?) in termini delle caratteristiche sopra descritte rispetto all'approccio basato sull'input della dipendenza, poiché finisce per accoppiare le classi non solo a ConfigBlocks
, ma direttamente a un specifica istanza di esso. Ciò degrada ulteriormente l'applicabilità / deployability / testability.
Il mio consiglio generale sarebbe di sbagliare dal progettare interfacce che non dipendono da questi tipi di monoliti per fornire i loro parametri, almeno per le classi più generalmente applicabili che progettate. Evita l'approccio globale senza un'iniezione di dipendenza, se puoi, a meno che tu non abbia davvero una ragione molto strong e sicura per non evitarlo.