2009-10-16 11 views
8

Tengo un objeto llamado Parámetros que se arroja de método en método hacia abajo y hacia arriba en el árbol de llamadas, a través de los límites del paquete. Tiene alrededor de cincuenta variables de estado. Cada método puede usar una o dos variables para controlar su salida.Objeto de Dios: disminuir el acoplamiento a un objeto 'maestro'

Creo que esta es una mala idea, porque no puedo ver fácilmente qué método necesita para funcionar, o incluso lo que podría suceder si con una cierta combinación de parámetros para el módulo Y que no tiene relación con mi módulo actual.

¿Cuáles son algunas buenas técnicas para disminuir el acoplamiento a este objeto divino 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 
      { 

La persona que llama haría:

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

¿Es "Parámetros" un objeto de configuración? –

+0

Sí, lo es. Solía ​​tener la interfaz de usuario con los parámetros que la capa de negocios podría necesitar. –

Respuesta

9

Primero, a riesgo de afirmar lo obvio: pasar los parámetros que son utilizados por el métodos, en lugar del objeto dios.

Esto, sin embargo, puede llevar a que algunos métodos necesiten grandes cantidades de parámetros porque llaman a otros métodos, que llaman a otros métodos alternativamente, etcétera. Esa fue probablemente la inspiración para poner todo en un objeto divino. Daré un ejemplo simplificado de tal método con demasiados parámetros; que tendrá que imaginar que "demasiados" == 3 aquí :-)

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

Entonces la pregunta es, ¿Cómo podemos reducir la cantidad de parámetros sin tener que recurrir a un objeto de dios? La respuesta es deshacerse de la programación de procedimientos y hacer un buen uso del diseño orientado a objetos. Los objetos se pueden utilizar entre sí sin necesidad de conocer los parámetros que se utilizan para inicializar sus colaboradores:

// 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); 

Ahora el método FilteredReportPrinter.Print se puede implementar con un solo parámetro:

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

Por cierto, este El tipo de separación de preocupaciones y la inyección de dependencia es bueno para algo más que la eliminación de parámetros. Si accede a colaborador de objetos a través de interfaces, a continuación, que hace que su clase

  • muy flexible: puede configurar FilteredReportPrinter con cualquier aplicación de filtro/impresora se puede imaginar
  • muy comprobable: se puede pasar en colaboradores simulacros con enlatados respuestas y verificar que se usaron correctamente en una prueba de unidad
+1

La mejor respuesta, en mi opinión. –

0

de consulta cada cliente por sus parámetros necesarios e inyectarlos?

Ejemplo: cada "objeto" que requiere "parámetros" es un "Cliente". Cada "Cliente" expone una interfaz a través de la cual un "Agente de configuración" consulta al Cliente sus parámetros requeridos. El Agente de configuración luego "inyecta" los parámetros (y solo aquellos requeridos por un Cliente).

+0

¿Puedes ampliar esto, quizás con un ejemplo? Creo que estoy de acuerdo con esto, pero quiero estar seguro. – gn22

+0

No entiendo. –

+0

He agregado detalles. – jldupont

1

Si todos sus métodos utilizan la misma clase Parameters, entonces tal vez debería ser una variable miembro de una clase con los métodos pertinentes, luego puede pasar Parameters al constructor de esta clase, asígnelo a una variable miembro y todos sus métodos pueden usarlo para tener que pasarlo como un parámetro.

Una buena manera de comenzar a refactorizar esta clase de dioses es dividiéndola en pedazos más pequeños. Encuentre grupos de propiedades relacionadas y divídalas en su propia clase.

Puede volver a visitar los métodos que dependen de Parameters y ver si puede reemplazarlo con una de las clases más pequeñas que creó.

Difícil de dar una buena solución sin algunas muestras de código y situaciones del mundo real.

0

Parece que no está aplicando principios orientados a objetos (OO) en su diseño. Como mencionas la palabra "objeto", supongo que estás trabajando en algún tipo de paradigma OO. Te recomiendo que conviertas tu "árbol de llamadas" en objetos que modelen el problema que estás resolviendo. Un "objeto de dios" definitivamente es algo que debe evitarse. Creo que puede que te estés perdiendo algo fundamental ... Si publicas algunos ejemplos de código, puedo responder con más detalles.

+0

Sí, bueno, es un sistema heredado, y está mal escrito, estoy de acuerdo. –

+1

Por favor, publique un ejemplo de código ... cómo lidia con esta situación depende de los detalles. – SingleShot

-2

(supongo que esto está dentro de un entorno Java o .NET) Convierta la clase en un singleton. Agregue un método estático llamado "getInstance()" o algo similar para llamar para obtener el paquete de nombre y valor (y deje de "recorrerlo"; consulte el capítulo 10 del libro "Code Complete").

Ahora la parte difícil. Presumiblemente, esto se encuentra dentro de una aplicación web o en algún otro entorno no por lotes/de un único subproceso. Entonces, para obtener acceso a la instancia correcta cuando el objeto no es realmente un singleton verdadero, debe ocultar la lógica de selección dentro del acceso estático.

En java, puede configurar una referencia "hilo local" e inicializarla cuando se inicie cada solicitud o subtarea. Luego, codifique el acceso en términos de ese thread-local. No sé si existe algo análogo en .NET, pero siempre puede simularlo con un diccionario (Hash, Map) que utiliza la instancia de la secuencia actual como clave.

Es un comienzo ...(siempre hay descomposición del blob, pero construí un framework que tiene un valor-store semi-global muy similar dentro de él)

+3

Estoy tratando de evitar tener un singleton. De hecho, no me gustan los singleton debido a dónde lo he visto usado. Usarlo aquí sería un paso atrás. –

+0

-1 el hecho de que necesite threadlocal para reducir la "globalidad" del "singleton" indica que no debe usar globales en primer lugar. El OP puede estar hablando de una aplicación winforms de subproceso único de todos modos. –

0

Para los parámetros que dictan el comportamiento, se puede crear una instancia de un objeto que muestre el comportamiento configurado. Entonces las clases de clientes simplemente usan el objeto instanciado, ni el cliente ni el servicio tienen que saber cuál es el valor del parámetro. Por ejemplo, para un parámetro que indique dónde leer los datos, haga que FlatFileReader, XMLFileReader y DatabaseReader hereden la misma clase base (o implementen la misma interfaz). Cree una instancia de uno de ellos base en el valor del parámetro, luego los clientes de la clase lectora simplemente solicitan datos al objeto lector instanciado sin saber si los datos provienen de un archivo o de la base de datos.

Para empezar, puede dividir su gran clase ParametresExecution en varias clases, una por paquete, que solo contiene los parámetros del paquete.

Otra dirección podría ser pasar el objeto ParametresExecution en el momento de la construcción. No tendrá que pasarlo por alto en cada llamada a la función.

Cuestiones relacionadas