Supponendo che non stai cercando un quadro beffardo, perché sono ultra-ubiquitari e facili da trovare , ci sono alcune cose che vale la pena notare in anticipo:
- Non c'è "mai" qualcosa che dovresti "sempre" fare.
Non è sempre meglio avvolgere una libreria di terze parti. Se l'applicazione è intrinsecamente dipendente da una libreria o se è letteralmente costruita attorno a una o due librerie principali, non perdete tempo a impacchettarla. Se le librerie cambiano, l'applicazione dovrà comunque cambiare .
- È corretto utilizzare i test di integrazione.
Ciò è particolarmente vero attorno a limiti stabili, intrinseci alla propria applicazione o che non possono essere facilmente derisi. Se tali condizioni sono soddisfatte, il confezionamento e la derisione saranno complicati e noiosi. In tal caso, eviterei entrambi: non avvolgere e non deridere; basta scrivere test di integrazione. (Se il test automatico è un obiettivo.)
- Strumenti e framework non possono eliminare la complessità logica.
In linea di principio, uno strumento può essere ridotto solo sulla piastra della caldaia. Ma non esiste un algoritmo automatizzabile per prendere un'interfaccia complessa e renderla semplice - figuriamoci prendere l'interfaccia X e adattarla alle proprie esigenze. (Solo tu sai quell'algoritmo !) Quindi, mentre ci sono indubbiamente strumenti che possono generare wrapper sottili, suggerirei che non sono già onnipresenti perché, alla fine, devi ancora solo programmare in modo intelligente, e quindi manualmente, contro l'interfaccia anche se è nascosto dietro un wrapper.
Detto questo, ci sono tattiche che puoi usare in molte lingue per evitare di fare riferimento direttamente a una classe. E in alcuni casi, è possibile "fingere" un'interfaccia o un wrapper sottile che in realtà non esiste. In C #, ad esempio, vorrei seguire una delle due rotte:
- Usa una fabbrica e digitazione implicita .
Puoi evitare lo sforzo di avvolgere completamente una classe complessa con questa piccola combinazione:
// "factory"
class PdfDocumentFactory {
public static ExternalPDFLibraryDocument Build() {
return new ExternalPDFLibraryDocument();
}
}
// code that uses the factory.
class CoreBusinessEntity {
public void DoImportantThings() {
var doc = PdfDocumentFactory.Build();
// ... i have no idea what your lib does, so, I'm making stuff but.
// but, you can do whatever you want here without explicitly
// referring to the library's actual types.
doc.addHeader("Wee");
doc.getAllText().makeBiggerBy(4).makeBold().makeItalic();
return doc.exportBinaryStreamOrSomething();
}
}
Se puoi evitare di archiviare questi oggetti come membri, sia attraverso un approccio più "funzionale" sia memorizzandoli in un dizionario (o qualsiasi altra cosa ), questo approccio ha il vantaggio di verificare il tipo in fase di compilazione senza che le tue entità aziendali principali debbano sapere esattamente con quale classe stanno lavorando.
Tutto ciò che serve è che, al momento della compilazione, la classe restituita dalla propria fabbrica abbia effettivamente i metodi su cui sta utilizzando l'oggetto business.
- Usa la digitazione dinamica .
Questo è nella stessa maniera dell'uso della tipizzazione implicita , ma comporta un altro compromesso: perdi i controlli di tipo compilazione e ottieni la possibilità di aggiungere anonimamente dipendenze esterne come membri della classe e iniettare le tue dipendenze.
class CoreBusinessEntity {
dynamic Doc;
public void InjectDoc(dynamic Doc) {
Doc = doc;
}
public void DoImortantThings() {
Doc.addHeader("Wee");
Doc.getAllText().makeBiggerBy(4).makeBold().makeItalic();
return Doc.exportBinaryStreamOrSomething();
}
}
Con entrambe queste tattiche, quando arriva il momento di deridere ExternalPDFLibraryDocument
, come ho detto prima, hai del lavoro da fare - ma, è un lavoro che dovresti comunque fare . E, con questa costruzione, hai evitato noiosamente la definizione di centinaia di classi di involucri sottili. Hai semplicemente usato la libreria senza guardarla direttamente - per la maggior parte.
Detto questo, ci sono tre grandi ragioni per cui prenderei ancora in considerazione l'idea di racchiudere esplicitamente una libreria di terze parti, nessuna delle quali suggerirebbe di usare uno strumento o un framework:
- La libreria specifica non è intrinseca all'applicazione.
- Sarebbe molto costoso scambiare senza avvolgerlo.
- Non mi piace l'API stessa.
Se non ho qualche preoccupazione di livello in tutte e tre queste aree, non fai alcuno sforzo significativo per concludere. E, se hai qualche preoccupazione in tutte e tre le aree, un wrapper sottile generato automaticamente non sarà davvero d'aiuto.
Se hai deciso di concludere una libreria, l'uso più efficiente ed efficace del tuo tempo è costruire la tua applicazione sull'interfaccia che desideri ; non contro un'API esistente.
Detto in altro modo, segui i consigli classici: rinvia ogni decisione che puoi. Crea prima il "core" della tua applicazione. Codice contro interfacce che alla fine faranno quello che vuoi, che lo farà fine saranno soddisfatte da "materiale periferico" che non esiste ancora. Colmare le lacune secondo necessità.
Questo sforzo non può sentirsi come il tempo salvato; ma se ritieni di aver bisogno di un wrapper, questo è il modo più efficace per farlo in sicurezza.
Pensare in questo modo.
Devi programmare contro questa libreria in qualche angolo buio del tuo codice, anche se è chiuso. Se prendi in giro la libreria durante i test, c'è inevitabile sforzo manuale lì, anche se è finito. Ma ciò non significa che devi riconoscere direttamente quella libreria per nome in gran parte della tua applicazione.
TLDR
Se vale la pena avvolgere la biblioteca, usa le tattiche per evitare riferimenti diretti e diffusi alla tua biblioteca di terze parti, ma non prendere scorciatoie per generare involucri sottili. Costruisci prima la tua logica aziendale, sii deliberato sulle tue interfacce ed emergi organicamente i tuoi adattatori, se necessario.
E, se si tratta di esso, non abbiate paura dei test di integrazione. Sono un po 'più sfocati, ma offrono ancora prove del codice funzionante e possono ancora essere facilmente fatti per tenere a bada le regressioni.