2009-10-16 9 views
8

Ho un oggetto chiamato Parametri che viene lanciato dal metodo al metodo verso il basso e verso l'alto nell'albero delle chiamate, oltre i limiti del pacchetto. Ha circa cinquanta variabili di stato. Ogni metodo potrebbe utilizzare una o due variabili per controllarne l'output.Oggetto God - abbassa l'accoppiamento con un oggetto "master"

Penso che questa sia una pessima idea, perché non riesco a vedere facilmente quale metodo debba funzionare, o anche cosa potrebbe accadere se con una certa combinazione di parametri per il modulo Y che è totalmente estraneo al mio attuale modulo.

Quali sono alcune buone tecniche per ridurre l'accoppiamento con questo oggetto dio o idealmente eliminarlo?

 public void ExporterExcelParFonds(ParametresExecution parametres) 
    { 
     ApplicationExcel appExcel = null; 
     LogTool.Instance.ExceptionSoulevee = false; 


     bool inclureReferences = parametres.inclureReferences; 
     bool inclureBornes = parametres.inclureBornes; 
     DateTime dateDebut = parametres.date; 
     DateTime dateFin = parametres.dateFin; 

     try 
     { 
      LogTool.Instance.AfficherMessage(Variables.msg_GenerationRapportPortefeuilleReference); 

      bool fichiersPreparesAvecSucces = PreparerFichiers(parametres, Sections.exportExcelParFonds); 
      if (!fichiersPreparesAvecSucces) 
      { 
       parametres.afficherRapportApresGeneration = false; 
       LogTool.Instance.ExceptionSoulevee = true; 
      } 
      else 
      { 

Il chiamante farebbe:

   PortefeuillesReference pr = new PortefeuillesReference(); 
      pr.ExporterExcelParFonds(parametres); 
+0

"Parametri" è un oggetto di configurazione? –

+0

Sì, lo è. Utilizzato per fare in modo che l'interfaccia utente portasse tutti i parametri di cui il livello aziendale potrebbe avere bisogno. –

risposta

9

Innanzitutto, a rischio di affermare l'ovvio: passare i parametri che vengono utilizzati dal metodi, piuttosto che l'oggetto dio.

Questo, tuttavia, potrebbe portare ad alcuni metodi che richiedono enormi quantità di parametri perché chiamano altri metodi, che a loro volta chiamano altri metodi, eccetera. Questa è stata probabilmente l'ispirazione per mettere tutto in un oggetto divino. Darò un esempio semplificato di un tale metodo con troppi parametri; dovrete immaginare che "troppi" == 3 qui :-)

public void PrintFilteredReport(
    Data data, FilterCriteria criteria, ReportFormat format) 
{ 
    var filteredData = Filter(data, criteria); 
    PrintReport(filteredData, format); 
} 

Quindi la domanda è: come possiamo ridurre la quantità di parametri senza ricorrere a un oggetto di Dio? La risposta è liberarsi della programmazione procedurale e fare buon uso del design orientato agli oggetti. Gli oggetti possono utilizzare l'altro senza la necessità di conoscere i parametri che sono stati utilizzati per inizializzare loro collaboratori:

// dataFilter service object only needs to know the criteria 
var dataFilter = new DataFilter(criteria); 

// report printer service object only needs to know the format 
var reportPrinter = new ReportPrinter(format); 

// filteredReportPrinter service object is initialized with a 
// dataFilter and a reportPrinter service, but it doesn't need 
// to know which parameters those are using to do their job 
var filteredReportPrinter = new FilteredReportPrinter(dataFilter, reportPrinter); 

Ora il metodo FilteredReportPrinter.Print può essere implementato con un solo parametro:

public void Print(data) 
{ 
    var filteredData = this.dataFilter.Filter(data); 
    this.reportPrinter.Print(filteredData); 
} 

Per inciso, questo una sorta di separazione delle preoccupazioni e l'iniezione di dipendenza è buona per qualcosa di più della semplice eliminazione dei parametri. Se si accede collaboratore oggetti attraverso interfacce, allora che fa la classe

  • molto flessibile: è possibile impostare FilteredReportPrinter con qualsiasi implementazione di filtro/stampante che si possa immaginare
  • molto testabile: è possibile passare in collaboratori finti con scatola risposte e verificare che siano state utilizzate correttamente in un test unitario
+1

La migliore risposta, secondo me. –

0

Query ogni cliente per i loro parametri richiesti e li inietta?

Esempio: ogni "oggetto" che richiede "parametri" è un "Cliente". Ogni "Client" espone un'interfaccia attraverso la quale un "Agente di configurazione" interroga il Cliente per i suoi parametri richiesti. L'agente di configurazione quindi "inietta" i parametri (e solo quelli richiesti da un client).

+0

Puoi approfondire questo, magari con un esempio? Penso di essere d'accordo con questo, ma voglio essere sicuro. – gn22

+0

Non capisco. –

+0

Ho aggiunto dettagli. – jldupont

1

Se tutti i metodi utilizzano la stessa classe Parameters allora forse dovrebbe essere una variabile membro di una classe con i metodi pertinenti in essa, quindi è possibile passare Parameters nel costruttore di questa classe, assegnarlo a una variabile membro e tutti i tuoi metodi possono usarlo con il doverlo passare come parametro.

Un buon modo per iniziare a rifattorizzare questa classe di Dio è dividerlo in parti più piccole. Trova gruppi di proprietà correlate e suddividili nella loro classe.

È quindi possibile rivisitare i metodi che dipendono da Parameters e vedere se è possibile sostituirlo con una delle classi più piccole che sono state create.

Difficile dare una buona soluzione senza alcuni esempi di codice e situazioni del mondo reale.

0

Sembra che non stiate applicando i principi orientati agli oggetti (OO) nella progettazione. Dal momento che menzioni la parola "oggetto" presumo tu stia lavorando all'interno di una sorta di paradigma OO. Vi consiglio di convertire il vostro "albero delle chiamate" in oggetti che modellano il problema che state risolvendo. Un "oggetto dio" è sicuramente qualcosa da evitare. Penso che potresti perdere qualcosa di fondamentale ... Se pubblichi alcuni esempi di codice, potrei essere in grado di rispondere in modo più dettagliato.

+0

Sì, è un sistema legacy, ed è scritto male, sono d'accordo. –

+1

Inserisci un esempio di codice ... il modo in cui gestisci questa situazione dipende dai dettagli. – SingleShot

-2

(presumo che sia all'interno di un ambiente Java o .NET) Convertire la classe in un singleton. Aggiungi un metodo statico chiamato "getInstance()" o qualcosa di simile da chiamare per ottenere il bundle del valore del nome (e smettere di "tramping" intorno - vedi cap.10 del libro "Code Complete").

Ora la parte difficile. Presumibilmente, si tratta di un'app Web o di un altro ambiente non batch/single-thread. Quindi, per ottenere l'accesso all'istanza corretta quando l'oggetto non è realmente un singleton vero, è necessario nascondere la logica di selezione all'interno dell'accessorio statico.

In java, è possibile impostare un riferimento "filo locale" e inizializzarlo quando ogni richiesta o sottoprocesso inizia. Quindi, codificare l'accessor in termini di thread-local. Non so se esiste qualcosa di analogo in .NET, ma puoi sempre simularlo con un dizionario (hash, mappa) che usa l'istanza del thread corrente come chiave.

È un inizio ...(c'è sempre una scomposizione del blob stesso, ma ho costruito un framework che ha un valore semi-globale molto simile al suo interno)

+3

Sto cercando di evitare di avere un singleton. In realtà non mi piacciono i singleton a causa di dove l'ho visto usato. Usarlo qui sarebbe un passo indietro. –

+0

-1 il fatto che sia necessario il threadlocal per ridurre la "globalness" del "singleton" indica che non dovresti utilizzare globalmente in primo luogo. L'OP potrebbe comunque parlare di un'app winforms a thread singolo. –

0

Per i parametri che dettano il comportamento, è possibile creare un'istanza di un oggetto che presenta il comportamento configurato. Quindi le classi client utilizzano semplicemente l'oggetto istanziato - né il cliente né il servizio devono sapere qual è il valore del parametro. Ad esempio, per un parametro che indica dove leggere i dati, FlatFileReader, XMLFileReader e DatabaseReader ereditano tutti la stessa classe di base (o implementano la stessa interfaccia). Istanziare uno di essi in base al valore del parametro, quindi i client della classe reader richiedono semplicemente dati all'oggetto del lettore istanziato senza sapere se i dati provengono da un file o dal DB.

Per iniziare è possibile suddividere la grande classe ParametresExecution in diverse classi, una per pacchetto, che contiene solo i parametri per il pacchetto.

Un'altra direzione potrebbe essere quella di passare l'oggetto ParametresExecution in fase di costruzione. Non dovrai farlo passare ad ogni chiamata di funzione.

Problemi correlati