2009-05-06 11 views
6

En mi código, tienen los siguientes objetos:¿Cuál es la mejor forma de manejar dependencias circulares entre objetos?

  • ErrorManager - controla los errores han iniciado sesión en la aplicación
  • configmanager - controla cómo se obtiene la información de configuración

En En el proyecto en el que estoy trabajando, el ErrorManager necesita extraer información de configuración utilizando la instancia de ConfigManager, mientras que ConfigManager usa el ErrorManager en caso de que ocurra un error.

Por el momento, estoy haciendo lo siguiente en el código:

ErrorManager _errorManager = new CustomErrorManager(); 
ConfigManager _configManager = new CustomConfigManager(_errorManager); 
_errorManager.SetConfigurationManager(_configManager); 

¿Hay una manera para mí para limpiar esta referencia circular de dependencias?

+2

Por lo general, la abundancia de clases "Manager" indica un abuso del patrón Singleton y no un diseño orientado a objetos. – Tmdean

+1

Estoy usando un patrón de Singleton para responsabilidades específicas en la aplicación (es decir, gestión de errores y gestión de la configuración). La instancia única no se implementa a través de un patrón de fábrica, ya que estoy viendo posiblemente agregar un contenedor IOC a la aplicación en el futuro cercano para manejar las dependencias por mí. En este momento, me estoy enfocando en trabajar en las dependencias para que el contenedor IoC sea una adición fácil. – JamesEggers

Respuesta

3

que crearía la siguiente:

ErrorConfig _errorConfig = ...; 
// ErrorConfig is a new config object containing only ErrorManager Configuration 
ErrorManager _errorManager = new CustomErrorManager(_errorConfig); 
ConfigManager _configManager = new CustomConfigManager(_errorManager); 

Ahora, el ConfigManager se puede utilizar la lista para ejecutarse sin problemas ErrorManager bootstrapping donde el ErrorManager no está listo para controlar los errores.

2

Por lo general, las referencias circulares se limpian mejor mediante la refactorización de una tercera clase de la que ambas dependen. Por ejemplo, puede tener algo como esto:

BootstrapConfigManager _bcm = new BootstrapConfigManager(); 
ErrorManager _errorManager = new CustomErrorManager(_bcm); 
ConfigManager _configManager = new CustomConfigManager(_bcm, _errorManager); 
0

Refactorice su código. Probablemente pueda dividir las clases para aislar una parte que pueda inicializar primero y pasar a ambas clases.

0

Crearía un método de extensión para cada llamada AddRelationship, pasando el otro objeto como el parámetro.

El objeto pasado añadiría la relación y luego llamar al método AddRelationship del otro:

static void AddRelationship(this ConfigManager configMgr, ErrorManager errMgr) 
{ 
    this.ErrorManager = errMgr; 
    if (this != errMgr.ConfigManager) 
     errMgr.AddRelationship(this); 
} 

static void AddRelationship(this ErrorManager errMgr, ConfigManager configMgr) 
{ 
    this.ConfigManager = configMgr; 
    if (this != configManager.errMgr) 
     configMgr.AddRelationship(this); 
} 

Esto significa que se puede añadir la relación usando objeto.

ConfigManager cfg = new ConfigManager(); 
ErrorManager err = new ErrorManager(); 
//Assign using either: 
err.AddRelationship(cfg); 
//Or 
cfg.AddRelationship(err); 

También debe crear extensiones de RemoveRelationship.

static void RemoveRelationship(this ConfigManager configMgr, ErrorManager errMgr) 
{ 
    if (this.errorManager == errMgr) 
    { 
     this.errorManager = null; 
     if (errManager.configManager == this) 
      errMgr.RemoveRelationship(this); 
    } 
} 

static void RemoveRelationship(this ErrorManager errMgr, ConfigManager cfgMgr) 
{ 
    if (this.ConfigManager == cfgMgr) 
    { 
     this.configManager = null; 
     if (cfgMgr.errorManager == this) 
      cfgMgr.RemoveRelationship(this); 
    } 
} 

No sé que las referencias circulares son una buena práctica de codificación particular, pero esto debería resolver la cuestión, tal como solicitó.

+0

Si bien esto funcionaría como una posible solución, no funcionaría desde un punto de vista de contenedor IoC por lo que puedo decir; sin embargo, todavía estoy en el proceso de aprender un par de contenedores de IoC diferentes para poder estar equivocado. – JamesEggers

+0

Ah, no especificó eso en su pregunta original o podría no haber publicado. Todavía no he tenido tiempo para investigar los contenedores de IoC o la inyección de dependencia debido a otros requisitos del proyecto. – BenAlabaster

Cuestiones relacionadas