unity patron net manejo inyeccion framework dependencias asp c# c++ dependency-injection inversion-of-control loose-coupling

patron - manejo de dependencias c#



¿Es la inyección de dependencia útil en C++? (5)

Para esto, necesito una interfaz y tal vez un contenedor para resolver mis instancias. ¿Pero cómo haces esto en C ++?

Del mismo modo. La diferencia es que cuando "programa en una interfaz" en C #, "programa en una clase base" en C ++. Además, tiene herramientas adicionales en C ++ que no tiene en C # (por ejemplo, las plantillas basadas en políticas implementan la inyección de dependencia elegida en el momento de la compilación).

En C ++, se usa una referencia a un objeto, esta es la forma de usar DI en C ++, ¿verdad?

No; esta no es la forma de usar DI, esta es una forma de usar DI en C ++.

Considera también:

  • usar un puntero a un objeto (o puntero inteligente, según el caso)
  • use un argumento de plantilla para una política (para un ejemplo, vea std :: default_delete use in smart pointers)
  • use lambda calcullus con funtores / predicados inyectados.

En C # Tengo una "clase mala / proyecto / ensamblaje incorrecto" que registra todas mis instancias en un contenedor estático al inicio del programa.

Si entiendo correctamente, establece todos sus datos en este contenedor estático y lo utiliza en toda la aplicación. Si este es el caso, entonces no usa la inyección de dependencia correctamente, porque esto infringe la Ley de Demeter.

¿Es esto posible en C ++?

Sí, es perfectamente posible (pero no deberías hacerlo, ya que viola la ley de Demeter). Eche un vistazo a boost :: any (esto le permitirá almacenar objetos heterogéneos en un contenedor, similar a almacenar objetos por referencia de object en C #).

¿Está utilizando la inyección de dependencia o como se llame en C ++?

Sí (y se llama inyección de dependencia :)).

Si es así, ¿cómo lo usas?

Como describí anteriormente (argumentos de plantillas de políticas, funtores inyectados y predicados como componentes reutilizables, inyectando objetos por referencia, puntero inteligente o valor).

C # usa la inyección de dependencia (DI) mucho para tener una plataforma comprobable y sin pérdidas . Para esto, necesito una interface y tal vez un contenedor DI o Inversion of Control (IoC) para resolver mis instancias.

¿Pero cómo haces esto en C ++? He leído un poco sobre esto y parece que la inyección de dependencia en C ++ no es un tema tan importante como en C #. En C ++, utiliza una referencia a un objeto . Esta es la forma de usar DI en C ++, ¿verdad?

Si mi teoría con referencias es correcta, ¿hay algo así como un contenedor donde pueda resolver todas las referencias? En C # tengo una "bad class/bad project/assembly" que registra todas mis instancias en un contenedor estático al inicio del programa. Entonces, en cada clase, puedo crear una instancia del contenedor estático y puedo resolver una instancia específica, ¿es esto posible en C ++?

¿Está utilizando la inyección de dependencia (o como se llame) en C ++? Si es así, ¿cómo lo usas? ¿Hay similitudes con C #?


Si mi teoría con referencias es correcta, ¿hay algo así como un contenedor donde pueda resolver todas las referencias? En C # tengo una "clase mala / proyecto / ensamblaje incorrecto" que registra todas mis instancias en un contenedor estático al inicio del programa. Entonces, en cada clase, puedo crear una instancia del contenedor estático y puedo resolver una instancia específica, ¿es esto posible en C ++?

No es así como se supone que se utiliza el DI, no pasa su contenedor a toda su clase de "consumidor". En una aplicación bien diseñada, solo haces una pequeña resolución en el punto de entrada y eso es todo. La mayoría de las veces, la necesidad de una "resolución" se puede reemplazar con el uso de una fábrica que se registrará y luego se inyectará.

Tendrás muchos problemas para probar el código dependiendo de una clase estática. Le recomendaría que si realmente desea inyectar su contenedor en su clase de cliente al menos en una instancia e inyectarlo, las dependencias estáticas son un infierno, sería más fácil burlarse de las pruebas unitarias.


Con C ++ 11 como límite de proyecto, terminé rodando el mío. Lo basé libremente en .NET Ninject API sin el curso Reflection.

ServiceLocator

Tenga en cuenta que, aunque se llama ServiceLocator (ya que no realiza la inyección de dependencia en sí misma) si utiliza enlaces de función lambda y, preferiblemente, ServiceLocator: las clases de módulos se inyectan (no se basan en la reflexión) y funcionan realmente bien (IMO)

#include <iostream> #include <vector> #include "ServiceLocator.hpp" template <class T> using sptr = std::shared_ptr<T>; // Some plain interfaces class IFood { public: virtual std::string name() = 0; }; class IAnimal { public: virtual void eatFavouriteFood() = 0; }; // Concrete classes which implement our interfaces, these 2 have no dependancies class Banana : public IFood { public: std::string name() override { return "Banana"; } }; class Pizza : public IFood { public: std::string name() override { return "Pizza"; } }; // Monkey requires a favourite food, note it is not dependant on ServiceLocator class Monkey : public IAnimal { private: sptr<IFood> _food; public: Monkey(sptr<IFood> food) : _food(food) { } void eatFavouriteFood() override { std::cout << "Monkey eats " << _food->name() << "/n"; } }; // Human requires a favourite food, note it is not dependant on ServiceLocator class Human : public IAnimal { private: sptr<IFood> _food; public: Human(sptr<IFood> food) : _food(food) { } void eatFavouriteFood() override { std::cout << "Human eats " << _food->name() << "/n"; } }; /* The SLModule classes are ServiceLocator aware, and they are also intimate with the concrete classes they bind to and so know what dependancies are required to create instances */ class FoodSLModule : public ServiceLocator::Module { public: void load() override { bind<IFood>("Monkey").to<Banana>([] (SLContext_sptr slc) { return new Banana(); }); bind<IFood>("Human").to<Pizza>([] (SLContext_sptr slc) { return new Pizza(); }); } }; class AnimalsSLModule : public ServiceLocator::Module { public: void load() override { bind<IAnimal>("Human").to<Human>([] (SLContext_sptr slc) { return new Human(slc->resolve<IFood>("Human")); }); bind<IAnimal>("Monkey").to<Monkey>([] (SLContext_sptr slc) { return new Monkey(slc->resolve<IFood>("Monkey")); }); } }; int main(int argc, const char * argv[]) { auto sl = ServiceLocator::create(); sl->modules() .add<FoodSLModule>() .add<AnimalsSLModule>(); auto slc = sl->getContext(); std::vector<sptr<IAnimal>> animals; slc->resolveAll<IAnimal>(&animals); for(auto animal : animals) { animal->eatFavouriteFood(); } return 0; }


Sí, la inyección de dependencia también es útil en C ++. No hay ninguna razón para que no sea así, porque no requiere un lenguaje o sintaxis específicos, sino una arquitectura de clase orientada a objetos (al menos este es probablemente el caso más habitual).

Mientras que en C # solo hay "punteros" a los objetos asignados dinámicamente, C ++ tiene múltiples variantes, como variables locales "normales", múltiples tipos de punteros, referencias ... además, el concepto de movimiento semántico es muy relevante para esto.

En C ++, se usa una referencia a un objeto, esta es la forma de usar DI en C ++, ¿verdad?

No solo. Puedes usar lo que quieras siempre que puedas pasar algo a un método de clase y este algo existirá mientras lo haga el objeto de clase. Las tres posibilidades anteriores pueden hacer eso (cada una de ellas con ciertas restricciones)

¿Hay algo así como un contenedor donde pueda resolver todas estas referencias? En C # tengo una "clase mala / proyecto / ensamblaje incorrecto" que registra todas mis instancias en un contenedor estático

Tal vez te estás perdiendo el punto de inyección dependiente. No es lo mismo que un grupo de variables "globales". Pero sí, por supuesto, esto también es posible en C ++. Hay clases, hay static , y eso es todo lo que se necesita.


Usar la inyección de dependencia es bastante sencillo en C ++. Simplemente defina una interfaz (una clase base abstracta pura) que use como referencia o argumento de puntero (o puntero inteligente) para el constructor o la función de inicio de la clase en la que desea que se aplique la dependencia.

Luego, en la prueba unitaria, inyecte un objeto simulado (una instancia de una clase heredada de la clase de interfaz abstracta), y en el código real, inyecte una instancia de la clase real (también heredando de la misma clase de interfaz).

Pan comido.