Access
 sql >> Database >  >> RDS >> Access

Creazione di dipendenze facoltative

Nel mio articolo di ieri, ho introdotto il concetto di "Treno delle dipendenze". Questo è ciò che accade quando si importa una funzione dalla libreria del codice, ma si finisce per dover importare diversi moduli aggiuntivi solo per soddisfare tutte le dipendenze. Ti rimane un intero "treno" di moduli di codice quando tutto ciò di cui hai bisogno era un singolo "posto" (funzione).

Finisci in questa situazione quando i tuoi moduli sono strettamente accoppiati. Quindi cosa puoi fare al riguardo? Ci sono alcuni modi per gestire questa situazione.

Viola "non ripetere te stesso"

Un modo per preservare l'accoppiamento libero, che si traduce in più moduli "autonomi", consiste nel creare copie private delle funzioni dal modulo sorgente nel modulo chiamante. Ciò elimina la dipendenza tra i due moduli, ma produce codice ripetitivo.

Il concetto è semplice. Copiate la funzione dal suo modulo di codice primario. Quindi lo incolli nel modulo di chiamata ma lo contrassegni come privato per evitare ambiguità.

Questo ha senso nelle seguenti situazioni:

  • Metodi semplici senza logica complessa.
  • Procedure che difficilmente cambieranno.
  • Quando la routine fa parte di un modulo molto più grande e non hai bisogno di nessuna delle altre funzioni nel modulo. La copia di una funzione evita il rigonfiamento.

Questo approccio ha i seguenti svantaggi:

  • Se c'è è un bug nella funzione copiata, dovrai risolverlo in molti punti.
  • Hai una duplicazione del codice se finisci per importare comunque il modulo sorgente.

Scegli le tue battaglie

Ho fatto di tutto per mantenere tutti i moduli della mia libreria di codice standard completamente autonomi. Il problema era che provocava molta duplicazione del codice. Il motivo è che la maggior parte delle funzioni che stavo copiando su altri moduli per uso privato provenivano da moduli che stavo comunque importando nella mia applicazione.

Un ottimo esempio di questo è stato il mio StringFunctions modulo. Quel modulo ha diversi metodi semplici che esistono in gran parte per rendere il mio codice più leggibile. Ad esempio, ho un Conc() funzione che stavo includendo come funzione privata in più della metà dei moduli della mia libreria di codice.

Col tempo mi sono reso conto di aver incluso quelle StringFunctions modulo in tutti i miei progetti. Non ho mai introdotto una nuova dipendenza quando ho chiamato una funzione da quel modulo. Stavo perdendo tempo e introducendo codice duplicato con scarso o nessun vantaggio.

C'erano alcuni moduli di codice che potevo tranquillamente presumere sarebbero stati in ogni applicazione. Quelli erano i moduli con le funzioni che usavo più spesso. Ciò significava che molte di queste dipendenze potevano essere essenzialmente ignorate.

Ora mantengo una "libreria standard" di moduli di codice che importo in ogni nuovo progetto all'inizio. Chiamo liberamente funzioni da quei moduli ora con la certezza che non introdurrò nuove dipendenze.

Utilizza un token di commento univoco

Uno dei moduli nella mia "Libreria standard" è un modulo di classe (clsApp ) che include proprietà e metodi a livello di applicazione, come il nome utente corrente e il testo della barra del titolo. Espongo anche altri moduli di classe da clsApp , come clsStatus e clsRegistro , che forniscono un accesso più leggibile rispettivamente alla barra di stato di Access e al registro di Windows.

Tuttavia, non ho bisogno di accedere alla barra di stato o al registro di Windows in ogni progetto. Quindi, per evitare di creare una dipendenza da clsStatus o clsRegistro classi, vorrei commentare il codice che fa riferimento a quelle classi utilizzando un "token di commento" univoco.

Questo è più facile da dimostrare con un esempio:

' Notes     
' - Find and replace '$$ with blank to enable Status property (requires clsStatus)
' - Find and replace '&& with blank to enable Reg property (requires clsRegistry)

'$$Private m_objStatus As clsStatus
'&&Private m_objReg As clsRegistry

'$$Public Property Get Status() As clsStatus
'$$    Set Status = m_objStatus
'$$End Property

'&&Public Property Get Reg() As clsRegistry
'&&    Set Reg = m_objReg
'&&End Property

Private Sub Class_Initialize()
    '$$    Set m_objStatus = New clsStatus
    '&&    Set m_objReg = New clsRegistry
End Sub

Se volessi abilitare lo Status proprietà della classe sopra, potrei eseguire una ricerca e una sostituzione globale su '$$ .

Questo ha funzionato bene per un po', ma mi è sempre sembrato goffo. Probabilmente perché lo era. L'altra cosa da notare è che i token di commento dovrebbero essere univoci a livello globale in tutta la mia intera libreria di codici. Sarebbe stato un incubo di manutenzione se fossi rimasto a lungo con questo approccio.

Utilizza la compilazione condizionale

Un approccio molto più pulito è sfruttare la compilazione condizionale. Quelle sono le righe in VBA che iniziano con un segno cancelletto/hashtag ("#"). Le righe che iniziano con quel carattere sono soggette a "preelaborazione".

Che cos'è la preelaborazione? Questo è un passaggio che i linguaggi di programmazione fanno prima della compilazione. Quindi, prima che si verifichi qualsiasi controllo in fase di compilazione, le righe di preelaborazione vengono valutate. Questo ci consente di inserire codice che altrimenti non verrebbe compilato nei nostri progetti.

Come possiamo trarne vantaggio con le nostre librerie di codici? Ancora una volta, questo è più semplice da dimostrare con un esempio:

' Notes 
' - Replace the '$$ and '&& kludges with conditional compilation

#Const EnableStatusProperty = True  'If True, requires import of clsStatus class
#Const EnableRegProperty = False  'If True, requires import of clsRegistry class

#If EnableStatusProperty Then
Private m_objStatus As clsStatus
#End If
#If EnableRegProperty Then
Private m_objReg As clsRegistry
#End If

#If EnableStatusProperty Then
Public Property Get Status() As clsStatus
    Set Status = m_objStatus
End Property
#End If

#If EnableRegProperty Then
Public Property Get Reg() As clsRegistry
    Set Reg = m_objReg
End Property
#End If

Private Sub Class_Initialize()
#If EnableStatusProperty Then
    Set m_objStatus = New clsStatus
#End If
#If EnableRegProperty Then
    Set m_objReg = New clsRegistry
#End If
End Sub

Il meglio di entrambi i mondi

Come puoi vedere, questo è un modo molto pulito per evitare il problema del "Treno delle dipendenze".

Ci consente di creare dipendenze opzionali . Ogni pezzo di codice che si basa su un altro modulo della libreria di codice viene racchiuso in una compilazione condizionale #If ... Then istruzione. Le costanti di compilazione condizionali sono tutte elencate nella parte superiore del modulo di codice.

Ora, quando reimportiamo una versione aggiornata del nostro modulo libreria di codice, dobbiamo semplicemente esaminare e impostare i flag di compilazione condizionale su quello che c'era prima. Se non ricordiamo come sono stati impostati i flag, dovremmo essere in grado di continuare a compilare e modificare i flag fino alla completa compilazione del progetto.

E se utilizziamo il controllo della versione, non dobbiamo preoccuparci di dimenticare cosa c'era prima.