Инъекция зависимости - нужен более крупный пример? - PullRequest
3 голосов
/ 22 октября 2010

Я ищу более крупный пример внедрения зависимости и как это можно реализовать.Если класс A зависит от класса B и передает ссылку на класс C в конструктор B, не должен ли класс A также принимать ссылку на класс C в своем конструкторе?Это означает, что метод main в приложении должен действительно создавать все классы, что звучит странно?

Я понимаю, что с помощью DI-фреймворков мы можем каким-то образом иметь его в XML-файлах, но это звучит так, как будто сложно быстроВидите, какой тип это на самом деле?Особенно если это очень большое приложение.

Ответы [ 4 ]

2 голосов
/ 22 октября 2010

Вы правы, и каждая структура DI имеет свой способ управления им.

Некоторые используют атрибуты свойств и т. Д. Для обозначения зависимости, а затем «автоматически» предоставляют экземпляр правильного типа, в то время как другие (скажем, замок Виндзор для .net) допускают конфигурацию xml, свободные или другие методы для «подключениявверх "граф зависимостей.

Также нет, класс A принимает встроенную ссылку на экземпляр B, который был построен с использованием экземпляра C. A не должен ничего знать о C, если не предоставлен через B.

    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 голос
/ 25 октября 2010

Вот несколько примеров из языка PHP, надеюсь, это поможет вам понять

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

Из этого примера в методе getInstance() используется ключевое слово new, вы также можете сделать

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

Обновление:

Если честно, я никогда не использую Dependency Injection, так как все, что он делает, это передает объекты в классы для создания локальной области видимости.

Я стремлюсь создать глобальную сущность и хранить в ней объекты, поэтому они хранятся только в 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");
         }
    }
}

я вижу, что этот способ передачи объектов намного чище

1 голос
/ 22 октября 2010
  1. чтобы ответить на ваш вопрос о классах A, B и C, A нужна только ссылка на B.
  2. Большинство платформ DI не требуют использования XML для конфигурации. На самом деле, многие люди предпочитают не использовать его. Вы можете явно настроить вещи в коде или использовать какие-то соглашения или атрибуты для контейнера, чтобы определить, какие объекты должны удовлетворять зависимостям.
  3. Большинство DI-фреймворков имеют функцию "отложенной загрузки", чтобы избежать создания каждого отдельного класса заранее. Или вы можете добавить свои собственные объекты «фабрики или строителя», чтобы создавать вещи ближе к тому времени, когда они будут использоваться

Вы не сказали, какой язык вы используете. Мой пример ниже в C # с использованием контейнера Unity. (очевидно, вы обычно используете интерфейсы, а не конкретные типы):

container = new UnityContainer();
container.RegisterType<C>();
container.RegisterType<B>(); 
A a = container.Resolve<A>();
0 голосов
/ 16 июня 2015

Если кто-то все еще ищет хороший пример, который показывает DI без IoC Containers (DI бедняков), а также с IoC Container (Unity в этом примере) и регистрацию типов в коде, а также в XML, вы можете проверить это:https://dannyvanderkraan.wordpress.com/2015/06/15/real-world-example-of-dependeny-injection/

...