Il modello di progettazione del ponte separa l'implementazione dall'interfaccia di un programma.
Perché è vantaggioso?
Il modello di progettazione del ponte separa l'implementazione dall'interfaccia di un programma.
Perché è vantaggioso?
Risposte:
Ti permette di cambiare l'implementazione indipendentemente dall'interfaccia. Questo aiuta a gestire le mutevoli esigenze.
L'esempio classico è la sostituzione dell'implementazione di archiviazione sotto un'interfaccia con qualcosa di più grande, migliore, più veloce, più piccolo o altrimenti diverso senza dover cambiare il resto del sistema.
Oltre alla risposta di Daniel, separare l'interfaccia dall'implementazione attraverso concetti come il polimorfismo consente di creare diverse implementazioni della stessa interfaccia che fanno cose simili in modi diversi.
Ad esempio, molte lingue hanno il concetto di stream da qualche parte nella libreria standard. Un flusso è qualcosa che contiene dati per l'accesso seriale. Ha due operazioni di base: Leggi (carica il prossimo numero X di byte dallo stream) e Scrivi (aggiungi il numero X di byte di dati allo stream), e talvolta un terzo, Cerca (ripristina la "posizione corrente" dello stream in una nuova posizione).
È un concetto abbastanza semplice, ma pensa a tutte le cose che potresti farci. Il più ovvio è interagire con i file su disco. Un flusso di file consente di leggere i dati da un file o di scrivere su di esso. E se invece volessi inviare dati tramite una connessione di rete?
Se hai fatto affidamento direttamente sulle implementazioni, dovresti scrivere due routine completamente diverse per salvare gli stessi dati in un file o inviarli in rete. Ma se hai un'interfaccia di flusso, puoi creare due diverse implementazioni di esso ( FileStream
e NetworkStream
) che incapsulano i dettagli specifici dell'invio dei dati dove devono andare, e quindi devi solo scrivere il codice che si occupa di salvare un file una volta . Improvvisamente your SaveToFile
e SendOverNetwork
routine sono molto più semplici: impostano semplicemente un flusso del tipo appropriato e lo passano alla SaveData
routine, che accetta un'interfaccia di flusso - non ha bisogno di preoccuparsi di quale tipo, purché possa eseguire il Scrivi operazione - e salva i dati nel flusso.
Ciò significa anche che se il formato dei dati cambia, non è necessario modificarlo in più luoghi diversi. Se centralizzi il tuo codice di salvataggio dei dati in una routine che accetta un flusso, questo è l'unico posto in cui deve essere aggiornato, quindi non puoi introdurre accidentalmente un bug cambiando solo un posto quando è necessario cambiare entrambi. Quindi separare le interfacce dalle implementazioni e usare il polimorfismo rende il codice più semplice da leggere e comprendere e che ha meno probabilità di avere bug.
IStream
, devi reinventare l'intero set di funzionalità per ogni stream. Ma se si inizia con una classe di flusso astratta di base, può contenere tutto lo stato e le funzionalità comuni e quindi consentire ai discendenti di implementare le caratteristiche distinte.
Hai davvero due domande molto diverse qui, sebbene siano correlate.
La domanda più generale è quella nel titolo, perché dovresti separare l'interfaccia dall'implementazione in generale. La seconda domanda è perché il modello a ponte è utile. Sono correlati perché il modello bridge è un modo specifico di separare l'interfaccia dall'implementazione, che ha anche alcune altre conseguenze specifiche.
La domanda generale è qualcosa di vitale da comprendere per ogni programmatore. È ciò che impedisce ai cambiamenti di un programma di propagarsi ovunque. Non riesco a immaginare che gli umani possano programmare senza usare questo.
Quando scrivi una semplice dichiarazione di addizione in un linguaggio di programmazione, questa è già un'astrazione (anche se non utilizza il sovraccarico dell'operatore per aggiungere matrici o qualcosa del genere) che passa attraverso un sacco di altro codice prima che venga finalmente eseguito su un circuito nel tuo computer. Se non vi fosse alcuna separazione dell'interfaccia (diciamo "3 + 5"), dall'implementazione (un gruppo di codice macchina), allora dovresti cambiare il tuo codice ogni volta che l'implementazione è cambiata (come se volessi eseguire su un nuovo processore).
Anche all'interno di una semplice applicazione CRUD, ogni firma del metodo è, in senso lato, l'interfaccia della sua implementazione.
Tutti questi tipi di astrazione hanno lo stesso obiettivo di base: far sì che il codice chiamante esprima le sue intenzioni nel modo più astratto possibile che fornisca all'implementatore tutte le informazioni necessarie. Ciò fornisce il minimo accoppiamento possibile tra loro e limita l'effetto di ondulazione quando il codice deve essere modificato il più possibile.
Sembra semplice, ma in pratica diventa complicato.
Il modello a ponte è un modo specifico di separare alcuni bit di implementazione in interfacce. Il diagramma di classe del modello è più informativo della descrizione. È più un modo per avere moduli collegabili che un bridge, ma lo hanno chiamato bridge perché è spesso usato dove i moduli sono stati creati prima dell'interfaccia. Quindi la creazione di un'interfaccia comune per implementazioni simili simili in qualche modo "colma" la differenza e consente al codice di lavorare con una qualsiasi delle implementazioni.
Quindi, supponiamo che tu voglia scrivere un componente aggiuntivo su un elaboratore di testi, ma vuoi che funzioni su più elaboratori di testi. È possibile creare un'interfaccia in grado di estrarre le funzionalità basate sull'elaboratore di testi necessarie (e che devono essere implementabili da ciascun elaboratore di testi poiché non è possibile modificarle) e un implementatore di tale interfaccia per ciascun elaboratore di testi che si desidera supportare. Quindi l'applicazione può chiamare quell'interfaccia e non preoccuparsi dei dettagli di ciascun word processor.
In realtà è leggermente più dettagliato di quello, perché ogni classe potrebbe davvero essere una gerarchia di classi (quindi, potrebbe non esserci solo un elaboratore di testi astratto, ma un Documento astratto, una TextSelection astratta, ecc., Con implementazioni concrete per ciascuno), ma è la stessa idea.
È un po 'come una facciata, tranne in questo caso lo strato di astrazione è focalizzato sulla fornitura della stessa interfaccia a più sistemi sottostanti.
È correlato a Inversion Of Control, poiché l'implementatore concreto verrà passato a metodi o costruttori e determinerà l'implementazione effettiva chiamata.