Зачем использовать фабричный шаблон, когда достаточно простого внедрения зависимостей

2

Я смотрю на этот пример, чтобы понять использование заводского шаблона.

Я действительно аматор в этой области, поэтому извините мой глупый вопрос.

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

В приведенном выше примере я бы сделал следующее:

public class Program
{
    // register the interfaces with DI container in a separate config class (Unity in this case)
    private readonly IShippingStrategy _shippingStrategy;

    public Program(IShippingStrategy shippingStrategy)
    {
        _shippingStrategy= shippingStrategy;
    }

    public int DoTheWork(Order order)
    {
        // assign properties just as an example
        order.ShippingMethod = "Fedex";
        order.OrderTotal = 90;
        order.OrderWeight = 12;
        order.OrderZipCode = 98109;

        int shippingCost = _shippingStrategy.CalculateShippingCost(order);

        return shippingCost;
    }
}

Вместо того, чтобы вводить завод:

public class Program
{
    // register the interfaces with DI container in a separate config class (Unity in this case)
    private readonly IShippingStrategyFactory _shippingStrategyFactory;

    public Program(IShippingStrategyFactory shippingStrategyFactory)
    {
        _shippingStrategyFactory = shippingStrategyFactory;
    }

    public int DoTheWork(Order order)
    {
        // assign properties just as an example
        order.ShippingMethod = "Fedex";
        order.OrderTotal = 90;
        order.OrderWeight = 12;
        order.OrderZipCode = 98109;

        IShippingStrategy shippingStrategy = _shippingStrategyFactory.GetShippingStrategy(order);
        int shippingCost = shippingStrategy.CalculateShippingCost(order);

        return shippingCost;
    }
}

Зачем брать bruden для создания фабрики (добавив дополнительный слой), когда мы можем вводить интерфейс непосредственно туда, где нам нужно его использовать?

  • 1
    Пожалуйста, объясните, как вы бы рассчитывали, что стратегия доставки будет зависеть от заказа, как видно из параметра к заводскому методу.
  • 1
    Внедрение зависимостей - это общая концепция, обычно DI реализуется с помощью DI Framework, которая, по сути, является просто общим шаблоном фабрики, который обеспечивает очень гибкую конфигурацию. Таким образом, по сути, DI Framework является завод. Но не все заводы DI Frameworks. Обычно под фабрикой понимается фабрика по индивидуальному заказу, настроенная для конкретной ситуации. Некоторые DI-фреймворки даже позволяют указывать пользовательские фабрики для более точного управления логикой.
Теги:
dependency-injection
design-patterns
factory-pattern

2 ответа

4

Я думаю, вам не нужна еще одна статья о фабричной схеме, но короткий всеобъемлющий ответ. Поэтому я хотел бы остановиться на двух вещах.

Больше гибкости

Чаще всего вы должны настроить свой корневой каталог, в котором вы в основном говорите...

"Если кто-то хочет IAnyService, он должен получить MyAnyServiceImplementation ".

Это исправлено для вашего приложения. После настройки ваш контейнер инъекций зависимостей будет обслуживать экземпляры классов, которые вы зарегистрировали, но вы не должны пытаться снова настроить этот контейнер. Это идеально подходит для гибкости запуска, например, для регистрации реализации компонентов доступа к данным с помощью конфигурации приложения. Сказать...

"Если кто-то хочет IUserRepository, он должен получить MsSqlUserRepository потому что мы работаем с сервером MSSQL".

Конечно, наличие этого "неизменяемого" корня композиции ограничивает возможности выбора реализации во время выполнения в зависимости от состояния приложений.

Вместо этого вы можете вводить класс, который принимает решение о текущем состоянии, которое должна выполнять реализация сервиса. Валидация данных является типичным сценарием для этого шаблона, поскольку в вашей системе могут быть разные правила для разных объектов. Здесь слово "шаблон правила" или "шаблон стратегии".

Контроль времени жизни

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

Скажем, вы хотите использовать репозиторий данных для подключения к базе данных, например. Эти вызовы доступа к базе данных должны быть короткими, и вы не хотите, чтобы соединения открывались в течение длительного времени. С фабрикой репозитория вы можете очень точно контролировать время жизни и убедиться, что класс удален после его использования:

using (var repository = new _factory.CreateRepository(...))
{
    return repository.GetAnything();
}

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

Фактически, есть вероятность, что репозиторий вообще не создается, если нет необходимости загружать данные (например, из-за хиджа в верхнем кэше). Если бы вы прямо ввели хранилище, вы гарантировали бы, что один длинный живой экземпляр живет в памяти в каждом случае.

  • 0
    Отличное объяснение. Я просто хочу выделить то, что вы сказали в разделе «Больше гибкости». Допустим, у меня есть интерфейс IUserRepository о котором вы говорили. Для меня преимущество, которое мы можем получить от использования фабричного шаблона, состоит в том, что у нас есть возможность использовать различные компоненты доступа к данным в одном приложении. Например, если у нас есть MsSqlUserRepository и AzurelUserRepository мы можем использовать их оба в одном приложении, используя фабричный шаблон, что невозможно, если мы напрямую IUserRepository верно?
  • 2
    Ммм ... не совсем. Вы можете использовать оба без завода. Однако вы можете принять решение только один раз при запуске приложения. Если вы настроены на использование MSSQL, используйте MsSqlUserRepository , если вы настроены для синхронизации с Azure, используйте AzureUserRepository . Как только процесс запущен, вы должны жить с ним. Наличие фабрики позволяет вам переключаться между этими двумя во время выполнения, но я думаю, что доступ к данным не лучший вариант для этого, потому что он вряд ли будет таким общим. Может быть, вы имели в виду то же самое, я не совсем уверен, правильно ли я понял «в том же приложении».
Показать ещё 1 комментарий
0

Если вы проверите код для фабрики, вы увидите, что в зависимости от метода ShippingMethod заказа другая фабрика IShippingStrategy возвращается. Поскольку метод ShippingMethod известен только после того, как DoTheWork был назван невозможным для внедрения правильной реализации при построении класса (и для одного и того же класса могут потребоваться разные реализации для разных заказов).

  • 0
    Итак, в двух словах, мы используем фабричный шаблон, когда не знаем, какую реализацию интерфейса использовать при его использовании? Я думаю, что при непосредственном введении интерфейса мы должны также указать (в другом месте, какую реализацию использовать), но я думаю, что это неправильно
  • 4
    Если вы можете привязать свой сервис к определенной зависимости, вы можете сделать это, используя регистрации, и в этом случае вы можете использовать DI. Но если правильное обслуживание зависит от используемых данных, заводской путь - это путь.
Показать ещё 1 комментарий

Ещё вопросы

Сообщество Overcoder
Наверх
Меню