Implementazione di un livello anti-corruzione con logica di dominio

1

Sto costruendo un'applicazione che compila un singolo documento PDF da più documenti PDF di origine come segue: prende la prima pagina di ogni documento sorgente, stampa alcune informazioni in cima a ciascuna di quelle pagine e quindi combina tutte quelle " prime pagine "in un documento PDF di output. Supponiamo che i PDF di origine esistano già.

Utilizzo una libreria di classi di terze parti per manipolare i PDF, ad esempio estrarre le prime pagine, applicare le informazioni stampate e combinare le pagine per generare il PDF risultante. Il mio obiettivo è mantenere le operazioni di manipolazione dei PDF indipendenti dal mio livello logico di dominio in modo che sia più facile scambiare la libreria di terze parti se necessario in futuro. Per questo, mi piacerebbe utilizzare un livello anti-corruzione.

Immagino che il mio dominio consisterà in una classe (a questo punto): PdfDocument . Il livello della logica di dominio carica una raccolta di% oggetti% di file da un altro tipo di flusso di input e fa uso di servizi esposti dal livello di anticorruzione per produrre un documento di output singolo con le caratteristiche che ho menzionato in precedenza. Posso immaginare due possibili modi di architettare questo:

  • espone i seguenti servizi distinti sul livello anti-corruzione: 1.) estrai la prima pagina di un documento PDF, cioè restituisci un PdfDocument che è una pagina, 2.) testo fornito da bollo in alto di un PdfDocument fornito, ovvero restituisce un nuovo PdfDocument che contiene il testo timbrato e 3.) combina più% oggetti% co_de in un PdfDocument , ovvero restituisce un nuovo PdfDocument che è tutte le pagine del file fornito PdfDocument s combinato.

  • espone un singolo servizio sul layer anti-corruzione che accetta una raccolta di PdfDocument s e restituisce un singolo PdfDocument con le caratteristiche sopra menzionate.

Il primo approccio sembra più in linea con la separazione delle preoccupazioni perché il secondo approccio dovrebbe assumere molte delle considerazioni logiche di dominio come "quante pagine estraggo?", "stampo ogni pagina?" e "quale delle pagine estratte da includere nell'output?". Tuttavia, il primo approccio è molto meno efficiente perché ogni servizio restituisce un PdfDocument . La libreria di terze parti che sto utilizzando ha una classe PdfDocument e una classe intermedia - PdfDocument - che rappresenta una pagina che appartiene a un intero PDF Document . Se utilizzo il primo approccio, la libreria di terze parti dovrebbe raggruppare tutto in un Page e quindi generare un Document per ciascun servizio. Tuttavia, se utilizzo il secondo approccio, posso operare in modo più efficiente su ciascun PDF perché i PDF di input possono essere suddivisi in Document oggetti a cui i timbri potrebbero quindi essere applicati direttamente e quegli oggetti PdfDocument potrebbero quindi essere combinati nel risultante Page e solo successivamente restituiti come Page .

Ho preso in considerazione l'aggiunta di una classe Document al mio modello come una soluzione a questo, ma il mio modello sta assumendo preoccupazioni che non dovrebbe necessariamente avere. Non ho bisogno della nozione di "pagina" nel mio modello se non per facilitare un uso più efficiente della libreria di terze parti, e questo, per me, sconfigge lo scopo del livello anti-corruzione.

Per favore aiutami a superare questo!

    
posta rory.ap 06.03.2015 - 19:23
fonte

2 risposte

5

Sembra che tu stia cercando di creare un adattatore attorno a una libreria di terze parti per evitare che si unisca nella tua logica aziendale. Tra i due approcci citati, il primo sembra l'idea migliore, poiché è il più flessibile e puoi separare la logica di business dall'adattatore (ovvero l'adattatore sarà fondamentalmente un passaggio alla libreria di terze parti).

Tuttavia, ti piacerebbe approfittare di un possibile stato intermedio di elaborazione offerto dalla biblioteca. Un modo per farlo potrebbe essere utilizzare il modello di build .

Adapter.CreateBuilder() -> returns the builder object
Builder.AddFirstPageFromDocument(binary data) -> returns the page number
Builder.StampPage(page number, message)
Adapter.CreateDocument(builder)

Questo è solo un breve esempio, è possibile nascondere tutti gli adattatori all'interno dell'oggetto builder o ogni metodo potrebbe vivere nell'adattatore e si passerebbe il builder a ciascun metodo (nel qual caso diventa piuttosto un oggetto stato / contesto piuttosto di un oggetto costruttore).

Se non ti senti ancora a tuo agio con l'introduzione di oggetti aggiuntivi nel tuo dominio, tuttavia, sacrificherei senz'altro l'efficienza per una separazione netta (ad esempio, segui la prima opzione e restituisci l'intero documento ogni volta), puramente dal punto di vista della manutenzione .

    
risposta data 07.03.2015 - 08:54
fonte
1

Il tuo primo approccio sembra molto più pulito del secondo, ma non penso che tu debba sacrificare necessariamente le prestazioni scegliendo questo design.

Supponendo che l'approccio non sia abbastanza efficiente, allora potresti usare il tuo PDFDocument come un'astrazione sulla tua rappresentazione pdf preferita "dietro le quinte". Quello che chiami PDFDocument , non deve essere esattamente ciò che la tua libreria di terze parti chiama un documento, quindi potrebbe alternativamente essere un certo intervallo di pagine all'interno di quest'ultimo. Se segui questa strada, l'estrazione della prima pagina da una PDFDocument può essere implementata internamente semplicemente impostando l'intervallo di pagine da "pagina 1 a pagina 1", senza creare un nuovo originale "oggetto documento di terze parti". L'operazione di timbro quindi internamente deve fare uso di quell'intervallo di pagine, così come l'unione finale.

Quindi suppongo che dovrebbe essere possibile avere entrambi: una semplice rappresentazione per PDFDocument s nel livello dell'adattatore e l'utilizzo delle ottimizzazioni interne fornite dal fornitore della libreria senza esporle al tuo livello dominio.

    
risposta data 07.03.2015 - 09:28
fonte