Кто-либо может объяснить мне, подробно, как использовать контейнеры IOC?

Это 2016 , вы можете использовать черту , которая поможет вам расширить один и тот же класс несколькими библиотеками.

<?php

namespace iBasit\ToolsBundle\Utils\Lib;

use Doctrine\Bundle\DoctrineBundle\Registry;
use Symfony\Component\DependencyInjection\ContainerInterface;

trait Container
{
    private $container;

    public function setContainer (ContainerInterface $container)
    {
        $this->container = $container;
    }

    /**
     * Shortcut to return the Doctrine Registry service.
     *
     * @return Registry
     *
     * @throws \LogicException If DoctrineBundle is not available
     */
    protected function getDoctrine()
    {
        if (!$this->container->has('doctrine')) {
            throw new \LogicException('The DoctrineBundle is not registered in your application.');
        }

        return $this->container->get('doctrine');
    }

    /**
     * Get a user from the Security Token Storage.
     *
     * @return mixed
     *
     * @throws \LogicException If SecurityBundle is not available
     *
     * @see TokenInterface::getUser()
     */
    protected function getUser()
    {
        if (!$this->container->has('security.token_storage')) {
            throw new \LogicException('The SecurityBundle is not registered in your application.');
        }

        if (null === $token = $this->container->get('security.token_storage')->getToken()) {
            return;
        }

        if (!is_object($user = $token->getUser())) {
            // e.g. anonymous authentication
            return;
        }

        return $user;
    }

    /**
     * Returns true if the service id is defined.
     *
     * @param string $id The service id
     *
     * @return bool true if the service id is defined, false otherwise
     */
    protected function has ($id)
    {
        return $this->container->has($id);
    }

    /**
     * Gets a container service by its id.
     *
     * @param string $id The service id
     *
     * @return object The service
     */
    protected function get ($id)
    {
        if ('request' === $id)
        {
            @trigger_error('The "request" service is deprecated and will be removed in 3.0. Add a typehint for Symfony\\Component\\HttpFoundation\\Request to your controller parameters to retrieve the request instead.', E_USER_DEPRECATED);
        }

        return $this->container->get($id);
    }

    /**
     * Gets a container configuration parameter by its name.
     *
     * @param string $name The parameter name
     *
     * @return mixed
     */
    protected function getParameter ($name)
    {
        return $this->container->getParameter($name);
    }
}

Ваш объект, который будет обслуживать.

namespace AppBundle\Utils;

use iBasit\ToolsBundle\Utils\Lib\Container;

class myObject
{
    use Container;
}

Настройки вашего сервиса

 myObject: 
        class: AppBundle\Utils\myObject
        calls:
            - [setContainer, ["@service_container"]]

Позвоните в сервис в контроллере

$myObject = $this->get('myObject');
13
задан 23 May 2009 в 22:10
поделиться

7 ответов

Если у вас есть более сотни классов, реализующих общий интерфейс, IoC не очень поможет, вам нужна фабрика. Таким образом, вы можете сделать следующее:

public interface IMyInterface{
    //...
}

public class Factory{

    public static IMyInterface GetObject(string param){
        // param is a parameter that will help the Factory decide what object to return
        // (that is only an example, there may not be any parameter at all)
    }
}

//...
// You do not depend on a particular implementation here
IMyInterface obj = Factory.GetObject("some param");

Внутри фабрики вы можете использовать контейнер IoC для извлечения объектов, если хотите, но вам нужно будет зарегистрировать каждый из классов, реализующих данный интерфейс, и связать их для некоторых ключей (и использовать эти ключи в качестве параметров в методе GetObject ()).

IoC особенно полезен, когда вам нужно получить объекты, реализующие различные интерфейсы:

IMyInteface myObject = Container.GetObject<IMyInterface>();
IMyOtherInterface myOtherObject Container.GetObject<IMyOtherInterface>();
ISomeOtherInterface someOtherObject = Container.GetObject<ISomeOtherInterface>();

Видите? Только один объект, чтобы получить несколько объектов разного типа и никаких ключей (сами интерфейсы являются ключами). Если вам нужен объект для получения нескольких разных объектов, но все реализующие один и тот же интерфейс, IoC вам не очень поможет.

3
ответ дан 1 December 2019 в 22:24
поделиться

Инверсия управления в первую очередь касается управления зависимостями и предоставления тестируемого кода. При классическом подходе, если у класса есть зависимость, естественная тенденция - дать классу, который имеет зависимость, прямой контроль над управлением своими зависимостями. Обычно это означает, что класс, у которого есть зависимость, будет «обновлять» свои зависимости в конструкторе или по запросу в своих методах.

Инверсия управления - это просто ... она инвертирует то, что создает зависимости, экстернализируя этот процесс и внедряя их в класс, имеющий зависимость. Обычно сущность, которая создает зависимости, - это то, что мы называем контейнером IoC, который отвечает не только за создание и внедрение зависимостей, но и за управление их сроками жизни, определение их образа жизни (подробнее об этом через секунду), а также предлагает множество других возможностей. (Это основано на Castle MicroKernel / Windsor, который является моим предпочтительным контейнером IoC ... его прочно написанный, очень функциональный и расширяемый. Существуют и другие контейнеры IoC, которые проще, если у вас есть более простые потребности, например Ninject, Microsoft Unity и Spring.NET.)

Учтите, что у вас есть внутреннее приложение, которое можно использовать либо в локальном, либо в удаленном контексте. В зависимости от некоторых обнаруживаемых факторов вашему приложению может потребоваться загрузить «локальные» реализации ваших сервисов, а в других случаях может потребоваться загрузить «удаленные» реализации ваших сервисов. Если вы последуете классическому подходу и создадите свои зависимости непосредственно внутри класса, который имеет эти зависимости, то этот класс будет вынужден нарушить два очень важных правила разработки программного обеспечения: Разделение проблем и единоличная ответственность. Вы пересекаете границы, вызывающие беспокойство, потому что ваш класс теперь заботится как о своей внутренней цели, так и о том, какие зависимости он должен создавать и как. Класс теперь также отвечает за многие вещи, а не за одну вещь, и имеет множество причин для изменения: изменяется его внутренняя цель, изменяется процесс создания его зависимостей, способ обнаружения изменений удаленных зависимостей, какие зависимости могут потребоваться его зависимостям. и т. д.

Инвертируя управление зависимостями, вы можете улучшить архитектуру вашей системы и поддерживать SoC и SR (или, возможно, добиться этого, когда вы ранее не могли этого сделать из-за зависимостей). Поскольку внешний объект, контейнер IoC, теперь контролирует, как создаются и внедряются ваши зависимости, вы также можете получить дополнительные возможности. Контейнер может управлять жизненными циклами ваших зависимостей, создавая и уничтожая их более гибкими способами, которые могут повысить эффективность. Вы также получаете возможность управлять стилем жизни ваших объектов. Если у вас есть тип зависимости, который создается, используется и возвращается на очень частой основе, но который имеет небольшое состояние или его отсутствие (скажем, фабрики), вы можете дать им объединенный образ жизни, который сообщит контейнеру автоматически создавать пул объектов для этого конкретного типа зависимости. Существует множество стилей жизни, и такой контейнер, как Castle Windsor, обычно дает вам возможность создавать свои собственные.

Лучшие контейнеры IoC, такие как Castle Windsor, также обеспечивают большую расширяемость. По умолчанию Windsor позволяет создавать экземпляры локальных типов. Можно создать средства, которые расширяют возможности создания типов Windsor для динамического создания прокси веб-служб и узлов служб WCF на лету, во время выполнения, устраняя необходимость создавать их вручную или статически с помощью таких инструментов, как svcutil (это то, что я сделал сам недавно .) Существует множество средств, обеспечивающих поддержку IoC существующими фреймворками, такими как NHibernate, ActiveRecord и т. Д.

Наконец, IoC применяет стиль кодирования, который обеспечивает возможность модульного тестирования кода. Одним из ключевых факторов в обеспечении возможности тестирования модулей кода является экстернализация управления зависимостями. Без возможности предоставления альтернативных (имитируемых, заглушенных и т. Д.) Зависимостей изолированное тестирование отдельной «единицы» кода является очень сложной задачей, поэтому интеграционное тестирование остается единственным альтернативным стилем автоматизированного тестирования. Поскольку IoC требует, чтобы ваши классы принимали зависимости посредством внедрения (конструктором, свойством или методом), каждый класс обычно, если не всегда, сводится к единственной ответственности, состоящей из должным образом разделенных проблем и полностью имитируемых зависимостей.

IoC = better архитектура, большая сплоченность, улучшенное разделение задач, классы, которые легче свести к одной ответственности, легко настраиваемые и взаимозаменяемые зависимости (часто без необходимости перекомпиляции кода), гибкие стили жизни зависимостей и управление временем жизни, а также код с возможностью модульного тестирования . IoC - это своего рода образ жизни ... философия, подход к решению типичных проблем и соответствие важнейшим передовым практикам, таким как SoC и SR.

Даже (точнее, особенно) с сотнями различных реализаций единого интерфейса IoC может многое предложить.

13
ответ дан 1 December 2019 в 22:24
поделиться

У меня нет ссылок, но могу предоставить вам пример:

У вас есть веб-контроллер, которому необходимо вызвать службу, имеющую уровень доступа к данным.

Теперь я понимаю, что в вашем коде вы сами создаете эти объекты во время компиляции. Вы используете достойный шаблон проектирования, но если вам когда-нибудь понадобится изменить реализацию, скажем, dao, вы должны войти в свой код и удалить код, который устанавливает эту зависимость, перекомпилировать / протестировать / развернуть. Но если бы вы использовали контейнер IOC, вы бы просто изменили класс в конфигурации и перезапустили приложение.

1
ответ дан 1 December 2019 в 22:24
поделиться

Джереми Фрей упускает из виду одну из главных причин использования контейнера IOC: он упрощает имитацию и тестирование кода.

Поощрение использования интерфейсов имеет множество других приятных преимуществ: лучшее разбиение на уровни, более легкое динамическое создание прокси для таких вещей, как декларативные транзакции, аспектно-ориентированное программирование и удаленное взаимодействие.

Если вы думаете, что IOC хорош только для замены вызовов на «новые», вы этого не получите.

1
ответ дан 1 December 2019 в 22:24
поделиться

Контейнеры IoC обычно выполняют инъекции зависимостей, что в некоторых проектах не имеет большого значения, но некоторые из фреймворков, которые предоставляют контейнеры IoC, предлагают другие услуги, которые оправдывают их использование. Castle, например, имеет полный список сервисов, помимо контейнера IoC, среди которых динамические прокси, управление транзакциями и средства NHibernate. Тогда я думаю, вам следует рассматривать контейнеры IoC как часть инфраструктуры приложения.

Вот почему я использую контейнер IoC: 1. писать модульные тесты станет проще. На самом деле вы пишете разные конфигурации, чтобы делать разные вещи. 2. Добавление разных плагинов для разных сценариев (например, для разных клиентов) 3. Перехват классов для добавления различных аспектов в наш код. 4. Поскольку мы используем NHibernate, средства управления транзакциями и NHibernate в Castle очень помогают при разработке и сопровождении нашего кода. Это похоже на то, как будто все технические аспекты нашего приложения обрабатываются с использованием инфраструктуры приложения, и у нас есть время подумать о том, чего на самом деле хотят клиенты.

0
ответ дан 1 December 2019 в 22:24
поделиться

В последние несколько недель я сделал решительный шаг от внедрения зависимостей к полной инверсии управления с помощью Castle, поэтому я понимаю, откуда исходит ваш вопрос.

Некоторые причины, по которым я не хотел бы использовать контейнер IOC:

  1. Это небольшой проект, который не собирается так сильно расти. Если существует соотношение 1: 1 между конструкторами и вызовами этих конструкторов, использование контейнера IOC не уменьшит объем кода, который мне нужно написать. Вы не нарушаете принцип «не повторяйся», пока не обнаружите, что копируете и вставляете точно такой же «var myObject = new MyClass (someInjectedDependency)» во второй раз.

  2. Возможно, мне придется адаптировать существующий код для облегчения загрузки в контейнеры IOC. Это наверное не Это необходимо до тех пор, пока вы не познакомитесь с некоторыми из более крутых функций аспектно-ориентированного программирования, но если вы забыли сделать метод виртуальным, запечатайте его класс, и он не реализует интерфейс, и вам неудобно делать эти изменения из-за существующих зависимостей, то переключение не столь привлекательно.

  3. Это добавляет дополнительную внешнюю зависимость моему проекту - и моей команде. Я могу убедить остальную часть моей команды, что структурирование их кода, позволяющее DI, отличное решение, но в настоящее время я единственный, кто знает, как работать с Castle. Для небольших и менее сложных проектов это не будет проблемой. Для более крупных проектов (которые, по иронии судьбы, извлекли бы наибольшую пользу из контейнеров IOC), если я не могу достаточно хорошо проповедовать, используя контейнер IOC, моя команда не станет независимой. Я не собираюсь никому помогать.

Некоторые из причин, по которым я не хотел бы возвращаться к обычному DI:

  1. Я могу добавить или убрать ведение журнала для любого количества моих классов без добавления какой-либо трассировки или заявление о регистрации. Возможность для моих классов переплетаться с дополнительными функциями без изменения этих классов - это очень мощный инструмент. Например:

    Ведение журнала: http://ayende.com/Blog/archive/2008/07/31/Logging--the-AOP-way.aspx

    Транзакции: http: / /www.codeproject.com/KB/architecture/introductioncastle.aspx (перейдите к разделу «Транзакции»)

  2. Castle, по крайней мере, настолько полезен при подключении классов к зависимостям, что было бы больно идти назад.

Например, отсутствует зависимость с Castle:

«Невозможно создать компонент MyClass как

Некоторые из причин, по которым я не хотел бы возвращаться к обычному DI:

  1. Я могу добавить или убрать ведение журнала для любого числа моих классов, без добавления каких-либо инструкций трассировки или регистрации. Возможность для моих классов переплетаться с дополнительными функциями без изменения этих классов - это очень мощный инструмент. Например:

    Ведение журнала: http://ayende.com/Blog/archive/2008/07/31/Logging--the-AOP-way.aspx

    Транзакции: http: / /www.codeproject.com/KB/architecture/introductioncastle.aspx (перейдите к разделу «Транзакции»)

  2. Castle, по крайней мере, настолько полезен при подключении классов к зависимостям, что было бы больно идти назад.

Например, отсутствует зависимость с Castle:

«Невозможно создать компонент MyClass как

Некоторые из причин, по которым я не хотел бы возвращаться к обычному DI:

  1. Я могу добавить или убрать ведение журнала для любого числа моих классов, без добавления каких-либо инструкций трассировки или регистрации. Возможность для моих классов переплетаться с дополнительными функциями без изменения этих классов - это очень мощный инструмент. Например:

    Ведение журнала: http://ayende.com/Blog/archive/2008/07/31/Logging--the-AOP-way.aspx

    Транзакции: http: / /www.codeproject.com/KB/architecture/introductioncastle.aspx (перейдите к разделу «Транзакции»)

  2. Castle, по крайней мере, настолько полезен при подключении классов к зависимостям, что было бы больно идти назад.

Например, отсутствует зависимость с Castle:

«Невозможно создать компонент MyClass как Я не хочу возвращаться к обычному DI:

  1. Я могу добавить или убрать ведение журнала для любого количества моих классов без добавления каких-либо инструкций трассировки или регистрации. Возможность для моих классов переплетаться с дополнительными функциями без изменения этих классов - это очень мощный инструмент. Например:

    Ведение журнала: http://ayende.com/Blog/archive/2008/07/31/Logging--the-AOP-way.aspx

    Транзакции: http: / /www.codeproject.com/KB/architecture/introductioncastle.aspx (перейдите к разделу «Транзакции»)

  2. Castle, по крайней мере, настолько полезен при подключении классов к зависимостям, что было бы больно идти назад.

Например, отсутствует зависимость с Castle:

«Невозможно создать компонент MyClass как Я не хочу возвращаться к обычному DI:

  1. Я могу добавить или убрать ведение журнала для любого количества моих классов без добавления каких-либо инструкций трассировки или регистрации. Возможность для моих классов переплетаться с дополнительными функциями без изменения этих классов - это очень мощный инструмент. Например:

    Ведение журнала: http://ayende.com/Blog/archive/2008/07/31/Logging--the-AOP-way.aspx

    Транзакции: http: / /www.codeproject.com/KB/architecture/introductioncastle.aspx (перейдите к разделу «Транзакции»)

  2. Castle, по крайней мере, настолько полезен при подключении классов к зависимостям, что было бы больно идти назад.

Например, отсутствует зависимость с Castle:

«Невозможно создать компонент MyClass как без добавления какой-либо трассировки или записи в журнал. Возможность для моих классов переплетаться с дополнительными функциями без изменения этих классов - это очень мощный инструмент. Например:

Ведение журнала: http://ayende.com/Blog/archive/2008/07/31/Logging--the-AOP-way.aspx

Транзакции: http: / /www.codeproject.com/KB/architecture/introductioncastle.aspx (перейдите к разделу «Транзакции»)

  • Castle, по крайней мере, настолько полезен при подключении классов к зависимостям, что было бы больно идти назад.

  • Например, отсутствует зависимость с Castle:

    «Невозможно создать компонент MyClass как без добавления какой-либо трассировки или записи в журнал. Возможность для моих классов переплетаться с дополнительными функциями без изменения этих классов - это очень мощный инструмент. Например:

    Ведение журнала: http://ayende.com/Blog/archive/2008/07/31/Logging--the-AOP-way.aspx

    Транзакции: http: / /www.codeproject.com/KB/architecture/introductioncastle.aspx (перейдите к разделу «Транзакции»)

  • Castle, по крайней мере, настолько полезен при подключении классов к зависимостям, что было бы больно идти назад.

  • Например, отсутствует зависимость с Castle:

    «Невозможно создать компонент MyClass как Возможность для моих классов переплетаться с дополнительными функциями без изменения этих классов - это очень мощный инструмент. Например:

    Ведение журнала: http://ayende.com/Blog/archive/2008/07/31/Logging--the-AOP-way.aspx

    Транзакции: http: / /www.codeproject.com/KB/architecture/introductioncastle.aspx (перейдите к разделу «Транзакции»)

  • Castle, по крайней мере, настолько полезен при подключении классов к зависимостям, что было бы больно идти назад.

  • Например, отсутствует зависимость с Castle:

    «Невозможно создать компонент MyClass как Возможность для моих классов переплетаться с дополнительными функциями без изменения этих классов - это очень мощный инструмент. Например:

    Ведение журнала: http://ayende.com/Blog/archive/2008/07/31/Logging--the-AOP-way.aspx

    Транзакции: http: / /www.codeproject.com/KB/architecture/introductioncastle.aspx (перейдите к разделу «Транзакции»)

  • Castle, по крайней мере, настолько полезен при подключении классов к зависимостям, что было бы больно идти назад.

  • Например, отсутствует зависимость с Castle:

    «Невозможно создать компонент MyClass как у него есть зависимости, которые нужно удовлетворить. Сервис ждет следующего зависимости:

    Услуги: - IMyService, который не был зарегистрирован. "

    Отсутствует зависимость без Castle:

    Ссылка на объект не установлена ​​на экземпляр объекта

    Dead Last: возможность заменять внедренные службы во время выполнения путем редактирования файла Xml. Я считаю, что это самая обсуждаемая особенность, но я рассматриваю ее как просто вишню на торте. Я бы предпочел соединить все свои сервисы в коде, но я уверен, что в будущем я столкнусь с головной болью, когда мое мнение изменится по этому поводу.

    Я признаю это - будучи новичком в IOC и Касл - я, наверное, только царапаю поверхность, но пока мне действительно нравится то, что я вижу. Я чувствую, что последние несколько проектов, которые я построил с его помощью, действительно способны реагировать на непредсказуемые изменения, которые происходят изо дня в день в моей компании, - чувство, которого у меня никогда не было раньше.

    3
    ответ дан 1 December 2019 в 22:24
    поделиться
    Другие вопросы по тегам:

    Похожие вопросы: