Domanda

Sto riorganizzando le strutture della mia directory ColdFusion e sono curioso di sapere come gli sviluppatori CF esperti stiano organizzando librerie di pacchetti più piccoli.

Non sono così curioso dei componenti elaborati (oggetti) come lo sono delle dozzine di piccole funzioni di utilità che costruiamo nel tempo.

  • Usi un singolo file di grandi dimensioni con funzioni e lo includi?
  • Usi un singolo file di grandi dimensioni come cfcomponent e chiami creatobject / cfinvoke?
  • Metti ogni cffunction di utility nel suo cfc e chiami createobject / cfinvoke?
  • Usi la sintassi dei taglib di cfimport?
  • Utilizzi i tag personalizzati o il cfmodule?
  • Hai un modo migliore?

Dato che non mi piace la sintassi dettagliata, ho solo parlato di un lib.cfm che ha un sacco di funzioni comuni in esso. Posso trasformarli in CFC raggruppati su cui posso creare oggetto solo per avere un migliore isolamento su ambiti variabili.

C'è un modo migliore per farlo?

È stato utile?

Soluzione

Questa è una ristampa di un post sul blog che ho fatto il 13 giugno 2007. Ho usato questo metodo per un bel po 'e funziona benissimo! YMMV.

A chi non piacciono le funzioni definite dall'utente (UDF)? Se hai fatto qualche programmazione, è probabile che tu l'abbia ampiamente utilizzato. Il problema più grande che le persone hanno con loro è come includerli e organizzarli nella tua applicazione.

Quello che ho scoperto che molte persone fanno è creare un Utils.cfc o UDFs.cfc e tagliare e incollare i loro UDF che vogliono usare nel componente come mostrato di seguito:

<!--- UDFs.cfc --->
<cfcomponent output="false">

<cffunction name="init" access="public” returntype="Any" output="false">
  <cfreturn this>
</cffunction>

<cffunction name="myUDF1" access="public" returntype="Any" output="false">
</cffunction>

<cffunction name="myUDF2" access="public" returntype="Any" output="false">
</cffunction>

</cfcomponent>

Dopo aver incollato tutti gli UDF che l'applicazione utilizzerà nel componente, sarà necessario rendere gli UDF disponibili per l'applicazione. Quasi tutti quelli che ho visto eseguono questo caricamento dal componente nell'ambito dell'applicazione. La seguente riga viene inserita in onApplicationStart() se si utilizza Application.cfc o semplicemente aggiungendolo in Application.cfm se lo si utilizza:

<cfset application.functions = CreateObject("component", "udfs").init()>

Qualunque sia quello che stai usando, Application.cfc o Application.cfm, i risultati sono gli stessi; tutti i tuoi UDF sono disponibili per la tua applicazione e puoi utilizzarli liberamente in tutto. L'unica differenza è il nome della variabile che usi. Uso application.functions, alcuni usano application.utils o application.udfs; & # 8217; non importa, ancora, i risultati sono gli stessi.

C'è un problema che ho con questo approccio, è ingombrante e il componente UDF diventerà enorme. Il problema di avere un file componente così grande è la modifica che diventa un incubo poiché scorrere migliaia di righe di codice non è molto divertente e ho anche notato che CFEclipse impantana in file enormi. Sicuramente il collasso del codice fornisce un po 'di sollievo, ma deve esserci un modo migliore.

Quello che volevo era avere un solo file per ogni UDF che stavo usando e un modo per caricare automaticamente la mia applicazione. Il motivo alla base di ciò era che se avessi avuto bisogno di modificare myUDF1, avrei potuto semplicemente aprire il file myUDF1.cfm e modificare ciò di cui avevo bisogno. Volevo anche essere in grado di catturare UDF da CFLib.org e inserirli nella mia applicazione senza dover modifica qualsiasi cosa. Se mai avessi bisogno di rimuovere un UDF dalla mia applicazione, sarebbe facile come cancellare il file UDF e reinizializzare la mia applicazione.

Per realizzare ciò che volevo, ho modificato il mio UDFs.cfc in 11 righe di codice:

<!--- UDFs.cfc --->
<cfcomponent output="false">

  <cfset variables.udfdir = GetDirectoryFromPath(GetCurrentTemplatePath()) & "udfs">
  <cfset variables.q = "">

  <cffunction name="init" access="public" returntype="Any" output="false">
    <cfreturn this>
  </cffunction>

  <cfdirectory action="list" directory="#variables.udfdir#" filter="*.cfm" name="variables.q">

  <cfoutput query="variables.q">
    <cfinclude template="udfs\#name#">
  </cfoutput>

</cfcomponent>

Quindi cosa sta succedendo esattamente?

In breve, ecco cosa sta succedendo & # 8217; Ho una directory chiamata udfs nella stessa directory in cui ho il mio UDFs.cfc. Questa è la directory in cui ho inserito tutti i miei file CFM UDF. Ciò che UDFs.cfc fa è scansionare questa directory quando viene chiamata e include automaticamente ogni file CFM che trova. Quindi carica automaticamente tutti gli UDF nella cartella UDF in sé (comunemente chiamato & Quot; mixin & Quot;).

Quindi il mio obiettivo è raggiunto! Ho ogni UDF nel suo file, quindi non devo scorrere un enorme file componente per trovarlo. Ora posso aprirlo e modificarlo facilmente. Osservando semplicemente la directory, so quali UDF utilizza la mia applicazione. Posso aggiungere automaticamente un UDF da CFLib.org semplicemente salvando il testo dal browser in un file nella directory. Inoltre, se non ho più bisogno di usare l'UDF nella mia applicazione, elimino semplicemente il file dalla directory e viene rimosso dalla mia applicazione durante il prossimo riavvio. Tutto questo senza dover toccare il file UDFs.cfc principale.

Di seguito è riportato un esempio dell'aspetto di uno dei file CFD UDF. Il file si chiama fullLeft.cfm e risiede nella directory UDFs.

<!--- fullLeft --->
<cffunction name="fullLeft" access="public" displayname="fullLeft" returntype="string" output="false">
  <cfargument name="str" type="string" required="true">
  <cfargument name="count" type="numeric" required="true">
  <cfif not refind("[[:space:]]", arguments.str) or (arguments.count gte len(arguments.str))>
    <cfreturn Left(arguments.str, arguments.count)>
  <cfelseif reFind("[[:space:]]",mid(arguments.str,arguments.count+1,1))>
    <cfreturn left(arguments.str,arguments.count)>
  <cfelse>
    <cfif count-refind("[[:space:]]", reverse(mid(arguments.str,1,arguments.count)))>
      <cfreturn Left(arguments.str, (arguments.count-refind("[[:space:]]", reverse(mid(str,1,arguments.count)))))>
    <cfelse>
      <cfreturn left(arguments.str,1)>
    </cfif>
  </cfif>
</cffunction>

Altri suggerimenti

Penso che questo dipenda dal tuo stile di programmazione, scegli quello che preferisci. Trovo che il modo più semplice sia in application.cfm, impostare una variabile nell'ambito dell'applicazione su un componente cf con tutte le mie funzioni di utilità:

<cfif not isDefined("application.utilities")>
    <cfset application.utilities = createObject("component", "Utilities")>
</cfif>

Ora puoi chiamare i metodi in application.utitlies da qualsiasi luogo. Nota che se apporti modifiche al tuo cfcomponent, devi aggiornare la variabile dell'applicazione con una nuova istanza di Utilità.

se stai usando Application.cfc (se non lo sei, ti consiglio vivamente di migrare da Application.cfm - è molto facile da fare) puoi costruire un baseComponent.cfc con tutti i tuoi metodi UDF e avere l'Applicazione. cfc eredita da baseComponent. quindi nel metodo onRequestStart imposta una variabile chiamata request.app = this;

per la richiesta di entità, è quindi possibile utilizzare request.app.methodname () per accedere all'UDF. è un modo molto carino e semplice di gestire le UDF

inoltre, se vuoi, puoi avere tutti i tuoi cfcs ereditati dalla stessa baseComponent in modo che tutti i tuoi cfcs abbiano quelle funzioni util come metodi nativi. rende i test di unità CFC molto facili perché i CFC non devono rispondere su un riferimento passato (iniettato) al componente UDf, ne sono deceduti!

una sfida con questo approccio è che l'attributo extends di un cfc non può essere un'espressione ... quindi, a seconda di come impacchettate i componenti, questo può essere difficile da implementare. il modo più semplice per gestirlo è con una mappatura coldfusion.

hth Jon

Usiamo i file .cfm per le librerie di funzioni e chiamiamo il file appropriato con cfinclude. Alcuni dei file .cfm sono stati scaricati da cflib.org e altri sono scritti da noi. I file si trovano in una directory denominata UDF che è una sottodirectory di un'altra directory mappata al carattere barra. L'affermazione di cfinclude è semplicemente:

<cfinclude template="/UDF/filename.cfm">

Questo approccio rende le funzioni disponibili per tutte le applicazioni sul server.

Preferiamo anche l'approccio di diverse piccole librerie. Ogni libreria è specifica per argomento (matematica, stringa, array di elenchi ecc.)

Opzione: usi un singolo file di grandi dimensioni con cffunctions e lo includi?

A: L'ho fatto ma lo faccio sempre meno. Mi piace trarre vantaggio dall'eredità e da cfcexplorer

Opzione: usi un singolo file di grandi dimensioni come cfcomponent e chiami creatobject / cfinvoke?

A: Sì, lo faccio spesso

Opzione: metti ogni cffunction di utility nel suo proprio cfc e chiami createobject / cfinvoke?

A: Potrei farlo se mi aspetto che ulteriori funzioni vengano aggiunte in seguito

Opzione: usi la sintassi dei taglib di cfimport?

A: Faccio le cose in quel modo

Opzione: usi i tag personalizzati

A: Non per molto tempo. i CFC sono migliori in questo

Opzione: o cfmodule?

A: Non per molto tempo. i CFC sono migliori in questo. caller. * scope può rendere difficile il debug

Mi rendo conto che questa è una vecchia domanda, ma uso un approccio un po 'diverso per questi problemi.

Funzione utility / approccio Singleton con 'Iniezione'

Creo un cfc 'core' o 'utility'. In esso impacco tutte le funzioni del mio tipo di utilità che sono:

  • Utilizzato frequentemente sempre e ovunque (come una funzione viewRecord() dao generica e una funzione checkSecurity() di base, et al.)
  • Sono funzioni di base che imho dovrebbero essere fondamentali in CF (come lpad(), capitalize(), et al)
  • Sono wrapper di alcuni tag che mi consentono di utilizzare cfscript in modo ubiquitario (come exit() che avvolge <cfexit>)

Su onApplicationStart(), creo un'istanza di questo oggetto e lo assegno all'ambito Application creando così una sorta di singleton statico.

Quindi, invece di estenderlo o includerlo nuovamente in quasi tutti i miei CFC, il che mi consente di utilizzare l'estensione per un tipo più tradizionale di eredità, inietto quindi questi metodi nel costruttore (l'init) di tutti i miei CFC che costruisco. Lo faccio chiamando un metodo sull'oggetto utility stesso tale che:

public/remote any function init() {
  structAppend( Variables, Application.MyApp.Objects.oCore.injectCoreMethods() ); 
  return this; // Return instance of this object
}

Il metodo injectCoreMethods() restituisce selettivamente una struttura delle funzioni di utilità che voglio praticamente estendere in tutti i miei oggetti. Non inserisce necessariamente tutti i metodi di utilità. Quelli usati meno frequentemente, incluso Application.MyApp.Objects.oCore.infrequentMethod() stesso, dovrebbero comunque essere indirizzati tramite il puntatore dell'applicazione singleton completo in modo tale che Variables.

Iniettando nell'ambito init(), che è protetto, questi metodi saranno effettivamente metodi privati. Quindi qualsiasi dump degli oggetti non mostrerà queste funzioni di utilità ma sarà perfettamente accessibile all'interno del cfc con tutti i suoi metodi diretti.

Organizzazione dei file:

In genere sono caduto nello schema di avere un cfc per cartella. In ogni cartella, ho un file cfc per il componente e l'init. Tutti gli altri metodi che ho suddiviso in file cfm e inclusi in quel cfc. Faccio questo per:

  1. Evita file giganti cfc di oltre 1000 righe che possono rallentare il mio IDE (uso aptana / cfeclipse)
  2. Consentire alle modifiche di essere registrate / tracciate in modo più discreto su base file per file e quindi registrate nel mio software di controllo SCM / versione.
  3. Consenti a più di una persona di lavorare su un determinato oggetto senza il codice di bump l'uno nell'altro.

Quindi un oggetto dao che contiene 4 metodi crud sarebbe simile a questo:

/code/dao/dao.cfc
/code/dao/_removeRecord.cfm
/code/dao/_addRecord.cfm
/code/dao/_viewRecord.cfm
/code/dao/_editRecord.cfm

Il cfc contiene solo i commenti _string.cfm e autocompattanti e nell'area pseudo-costruttore includo i quattro metodi. Questo mi permette anche di prendere qualsiasi cfc dalla sua cartella e spostarlo da qualche parte.

Lo stesso per l'utilità cfc. Si trova nella sua cartella e ha circa 30 funzioni dispari tra circa 10 file cfm (alcune semplici funzioni che lascio nello stesso file come rpad() che in realtà contiene <=>, <=>, ecc. Tutte le stringhe correlate. prendi l'idea.)

Moduli e tag personalizzati

Li evito a tutti i costi perché devono essere registrati e ostacolano il facile spostamento / implementazione. Non mi piacciono le cose che non si configurano da sole durante il trascinamento da un ambiente all'altro. CF5- hai dovuto fare le cose in questo modo molto di più. Ma dal momento che CF6 e la capacità di usare oggetti in un vero schema OOP, perché dovresti farlo? Ci sono pochissimi casi che vorresti / avresti bisogno.

Altro

Ho usato per mettere le funzioni 'core' in base.cfc che viene automaticamente esteso a tutti i cfc generati da CF (cercalo, aggiungi una funzione e voilà! Kinda piace aggiungere cose al prototipo in js). Mi piaceva molto, ma era un problema per l'implementazione / manutenzione.

In una certa misura, prendo un approccio Factory. Metto spesso nell'applicazione una discreta quantità di CFC statici come quello principale. Un controller legge una tabella di controllo generica e imposta tutti gli oggetti in un ciclo insieme a un sacco di altre cose all'avvio dell'app come variabili dell'app. Ma alcuni oggetti vengono istanziati secondo necessità, ovviamente oggetti pesanti e oggetti che contengono manipolazionei dati [semi] persistenti rientrano in quella categoria

Faccio questo, in un certo senso, dal CF7. Con CF9 + sta diventando abbastanza facile, maturo e lucido.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top