Pregunta

He estado tratando de seguir los principios de la inyección de dependencia, pero después de leer este artículo, sé que estoy haciendo algo mal.

Aquí está mi situación: Mi aplicación recibe diferentes tipos de correo físico. Todo el correo entrante pasa a través de mi objeto MailFunnel .

Mientras se está ejecutando, MailFunnel recibe diferentes tipos de mensajes desde el exterior: buzón, postal y revista.

Cada tipo de correo debe manejarse de manera diferente. Por ejemplo, si entra una caja, es posible que deba registrar el peso antes de entregarlo. En consecuencia, tengo los objetos BoxHandler , PostcardHandler y MagazineHandler .

Cada vez que entra un nuevo mensaje en mi MailFunnel , instancia un nuevo correspondiente MailHandler objeto.

Por ejemplo:

class MailFunnel
{
  void NewMailArrived( Mail mail )
  {
    switch (mail.type)
    {
      case BOX:
        BoxHandler * bob = new BoxHandler(shreddingPolicy, maxWeightPolicy);
        bob->get_to_work();
        break;

      case POSTCARD:
        PostcardHandler * frank = new PostcardHandler(coolPicturePolicy);
        frank->get_to_work();
        break;

      case MAGAZINE:
        MagazineHandler * nancy = new MagazineHandler(censorPolicy);
        nancy->get_to_work();
        break;
    }
  }

  private:
    MaxWeightPolcy & maxWeightPolicy;
    ShreddingPolicy & shreddingPolicy;
    CoolPicturePolicy & coolPicturePolicy;
    CensorPolicy & censorPolicy;
}

Por un lado, esto es genial porque significa que si recibo cinco correos diferentes, inmediatamente tengo cinco MailHandlers diferentes trabajando simultáneamente para ocuparse de los negocios. Sin embargo, esto también significa que I estoy mezclando la creación de objetos con la lógica de la aplicación , un gran no-no cuando se trata de la inyección de dependencia.

Además, tengo todas estas referencias de políticas en mi objeto MailFunnel que MailFunnel realmente no necesita. La única razón por la que MailFunnel tiene estos objetos es para pasarlos a los constructores MailHandler . Nuevamente, esta es otra cosa que quiero evitar .

Todas las recomendaciones son bienvenidas. Gracias!

¿Fue útil?

Solución

Esto me parece más una fábrica. Mueva la invocación del método get_to_work () fuera de la invocación y devuelva el controlador. El patrón funciona bastante bien para una fábrica.

class MailHandlerFactory
{
  IMailHandler*  GetHandler( Mail mail )
  {
    switch (mail.type)
    {
      case BOX:
        return new BoxHandler(shreddingPolicy, maxWeightPolicy);
        break;

      case POSTCARD:
        return new PostcardHandler(coolPicturePolicy);
        break;

      case MAGAZINE:
        return new MagazineHandler(censorPolicy);
        break;
    }
  }

  private:
    MaxWeightPolcy & maxWeightPolicy;
    ShreddingPolicy & shreddingPolicy;
    CoolPicturePolicy & coolPicturePolicy;
    CensorPolicy & censorPolicy;
}

class MailFunnel
{
    MailHandlerFactory* handlerFactory;

    MailFunnel( MailHandlerFactory* factory ) {
        handlerFactory = factory;
    }

    void NewMailArrived( Mail mail ) {
        IMailHandler handler = handlerFactory.GetHandler(mail);
        handler.get_to_work();
    }
}

Otros consejos

Cuando veas esa declaración de cambio, piensa en el polimorfismo. Este diseño solo puede ser extendido por modificación. Lo rehacería de tal manera que podría agregar un nuevo comportamiento agregando clases. Es de lo que trata el principio abierto / cerrado.

¿Por qué no puedes simplemente tener tres métodos que están sobrecargados que toman los diferentes tipos de correo y luego hacen lo apropiado? O haga que cada tipo se maneje solo.

De hecho, si tienes algo como el tipo, es probable que debas tener diferentes tipos.

Básicamente, haga lo siguiente:

1) Hacer el resumen de la clase Mail.

2) Cree tres subclases de correo, buzón, postal y revista

3) Dele a cada subclase un método para manejar el correo, o centralícelo en una HandlerFactory separada

4) Cuando se pasa al embudo de correo, simplemente haga que llame al método de manejo de correo, o haga que HandlerFactory le pase el correo y recupere el controlador apropiado. Nuevamente, en lugar de tener declaraciones de cambio incómodas en todas partes, use el lenguaje, para eso están los tipos y la sobrecarga de métodos.

Si su manejo de correo se vuelve complejo y desea eliminarlo, eventualmente puede hacer una clase de manejador de correo y extraer esas políticas en eso.

También puede considerar el uso de un método de plantilla, ya que la única diferencia real entre cada uno de ellos parece ser el controlador que usted crea, tal vez podría simplificarlo, de modo que el tipo de correo determina el controlador, el resto del código es básicamente lo mismo.

Es interesante que esté aplicando la inyección de dependencia a un proyecto de C ++; se ha realizado en otro lugar, una búsqueda rápida en Google encuentra un proyecto de código de Google Marco de otoño .

Pero la respuesta de tvanfosson es lo que sugeriría intentar primero, antes de adoptar un nuevo marco.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top