依赖注入 - 需要更大的例子吗?

时间:2010-10-22 13:43:38

标签: dependency-injection

我正在寻找一个更大的依赖注入示例以及如何实现它。如果类A依赖于类B并将类C的引用传递给B的构造函数,那么类A是否也必须在它的构造函数中引用类C?这意味着应用程序中的main方法应该真正创建所有类,听起来很奇怪?

据我所知,使用DI框架我们可以在某种程度上将它放在XML文件中,但听起来很难快速查看真正实例化的类型?特别是如果它是一个非常大的应用程序。

4 个答案:

答案 0 :(得分:2)

你是对的,每个DI框架都有不同的管理方式。

一些使用属性等属性来表示依赖,然后“自动”提供正确类型的实例,而其他(比如.net的城堡windsor)允许xml配置,流畅或其他方法“连接”依赖图。

同样不,A类对使用C实例构建的B实例进行构建引用。除非通过B公开,否则无需知道C语言。

    public class C { }

    public class B { public B(C c) { ... }}

    public class A { public A(B b) { ... }}

    // manual wireup
    C c = new C();
    B b = new B(c);
    A a = new A(b);

   // DI framework
   InversionOfControlContainer container = new InversionOfControlContainer(... some configuration);
   A a = container.ResolveInstanceOf<A>();
   // container dynamically resolves the dependencies of A. 
   // it doesnt matter if the dependency chain on A is 100 classes long or 3.
   // you need an instance of A and it will give you one. 

希望有所帮助。

答案 1 :(得分:1)

  1. 回答关于A,B和C类的问题,A只需要参考B。
  2. 大多数DI框架不要求您使用XML进行配置。事实上,很多人不喜欢使用它。您可以在代码中显式设置,或者使用容器的某种约定或属性来推断哪些对象应该满足依赖关系。
  3. 大多数DI框架都具有“延迟加载”功能,以避免预先创建每个单独的类。或者您可以注入自己的“工厂或构建器”对象来创建更接近使用时间的东西
  4. 你没说过你用的语言。下面我的例子是使用Unity容器的C#。 (显然通常你会使用接口而不是具体的类型):

    container = new UnityContainer();
    container.RegisterType<C>();
    container.RegisterType<B>(); 
    A a = container.Resolve<A>();
    

答案 2 :(得分:1)

这里有一些PHP语言的例子,希望这有助于你理解

class Users
{
    var $Database;
    public function __construct(Database $DB)
    {
        $this->Database = $DB;
    }
}
$Database = Database::getInstance();
$Users = new Users($Database);

在此示例中,new关键字用于方法getInstance(),您也可以

$Users = new Users(Database::getInstance());

或者解决这个问题的另一种方法是

class Users
{
    /*Dependencies*/
    private $database,$fileWriter;
    public function addDependency($Name,$Object)
    {
        $this->$Name = $Object;
        return $this;
    }
}
$Users = new Users();
$Users->addDependency('database',new Database)->addDependency('fileWriter',new FileWriter);

更新

老实说,我从不使用依赖注入,因为它所做的就是将对象传递给类来创建局部范围。

我倾向于创建一个全局实体,并在其中存储对象,因此只存储在1个变量中。

让我向您展示一个小例子:

abstract class Registry
{
    static $objects = array();
    public function get($name)
    {
        return isset(self::$objects[$name]) ? self::$objects[$name] : null;
    }

    public function set($name,$object)
    {
        self::$objects[$name] = $object;
    }
}

好的,这类课程的美妙之处在于

  • 非常轻量级
  • 它具有全球范围
  • 您可以存储资源等任何内容

当您的系统加载并且包含并初始化所有对象时,您可以将它们存储在这里,如下所示:

Registry::add('Database',new Database());
Registry::add('Reporter',new Reporter());

只要你在运行时,就可以像使用全局变量一样使用它:

class Users
{
    public function getUserById($id)
    {
         $query = "SELECT * FROM users WHERE user_id = :id";

         $resource = Registry::get("Database")->prepare($query);
         $resource->bindParam(':id',$id,PDO::PARAM_INT);

         if($resource->execute())
         {
              //etc
         }else
         {
              Registry::get('Reporter')->Add("Unable to select getUserById");
         }
    }
}

我看到这种对象传递方式更加清晰

答案 3 :(得分:0)

如果有人还在寻找一个很好的例子,它显示没有IoC容器的DI(穷人的DI)以及IoC容器(本例中为Unity)并在代码中注册类型,也可以用XML注册,你可以查看: https://dannyvanderkraan.wordpress.com/2015/06/15/real-world-example-of-dependeny-injection/