Рефакторинг на заводской метод - PullRequest
1 голос
/ 03 мая 2020

У меня есть блок кода внутри функции. Я хочу реорганизовать это, чтобы применить фабричный образец.

        IService service;     

        switch (path)
        {
            case ServicePath.service1:
                service = new service1(log, mappingConfig);
                return await service.ServiceTask();
            case ServicePath.service2:
                service = new service2(log, mappingConfig);
                return await service.ServiceTask();
            case ServicePath.service3:
                service = new service3(log, mappingConfig);
                return await service.ServiceTask();
            case ServicePath.service4:
                service = new service4(log, mappingConfig);
                return await service.ServiceTask();
        }

То, что я сделал, это

        class ServiceFactory
        {
            public static IService CreateService(String path, ILogger log, IConfig mappingConfig)
            {
                case ServicePath.service1:
                    return new service1(log, mappingConfig);
                case ServicePath.service2:
                    return new service2(log, mappingConfig);                    
                case ServicePath.service3:
                    return new service3(log, mappingConfig);
                case ServicePath.service4:
                    return new service4(log, mappingConfig);
            }
        }

, а затем метод вызова будет

    IService service = ServiceFactory.CreateService(path, log, mappingConfig);
    return await serviceFeature.ServiceTask();

Так что меня беспокоит, будет ли он все еще заводская модель? Если нет, то как реорганизовать это, чтобы оно было фабричным?

И я читаю везде, Factory Pattern и Dependency Injection выполняют одинаковую работу. Как реализовать мой код для внедрения зависимостей?

Ответы [ 3 ]

1 голос
/ 03 мая 2020

Реорганизованный код имеет тип: Simple Factory или Stati c Factory. Это был бы Фабричный шаблон, если у вас более одной Фабрики. То есть, скажем, ServiceFactory и ServiceFactory2, который также возвращает некоторые IService

Если вы уже знаете, как построить параметры (path, log, mappingConfig) перед собой, то вам следует придерживаться самого шаблона SimpleFactory. , Внедрение зависимости имеет больше смысла для меня, если объекты Parameters и его состояние являются динамическими c

1 голос
/ 03 мая 2020

Вы можете создать интерфейс для фабрики услуг и реализовать его (вместо использования метода c). Использование интерфейса позволяет внедрить эту зависимость в любой класс и покрыть ее UT

public interface IServiceFactory
{
    IService CreateService(string path, ILogger log, IConfig mappingConfig);
}

. Реализация может быть следующей

class ServiceFactory : IServiceFactory
{
    private readonly Dictionary<string, Func<ILogger, IConfig, IService>> _map;
    public ServiceFactory()
    {
        _map = new Dictionary<string, Func<ILogger, IConfig, IService>>();
        _map.Add(ServicePath.service1, (log, mappingConfig) => new service1(log, mappingConfig));
        _map.Add(ServicePath.service2, (log, mappingConfig) => new service2(log, mappingConfig));
        _map.Add(ServicePath.service3, (log, mappingConfig) => new service3(log, mappingConfig));
        _map.Add(ServicePath.service4, (log, mappingConfig) => new service4(log, mappingConfig));
    }

    public IService CreateService(string path, ILogger log, IConfig mappingConfig)
    {
        return _map.ContainsKey(path)
            ? _map[path](log, mappingConfig)
            : null; //or other default value
    }
}

Вместо оператора switch и нескольких case с ярлыками вы можете создать какую-то карту Dictionary<string, Func<ILogger, IConfig, IService>>, которая содержит служебный ключ и Func<ILogger, IConfig, IService> делегат для создания конкретного Service. В методе CreateService вы проверяете наличие служебного ключа в словаре и вызываете делегат Func для возврата конкретного экземпляра службы, в противном случае возвращаете null

1 голос
/ 03 мая 2020

Подход, который вы в настоящее время используете с ServiceFactory, по сути является абстрактной фабрикой, поскольку вы инкапсулируете создание связанного набора объектов в методе.

Существует несколько различных способов, которыми вы можете добиться аналогичных результатов с внедрением зависимости. Одно из основных преимуществ, которое вы получили бы от этого, заключается в том, что вам больше не нужно вручную создавать какие-либо из ваших классов обслуживания. Вот несколько примеров использования. NET Core DI framework:

Регистрация фабричного делегата

Вы можете зарегистрировать Func<string, IService>, который будет принимать строку и возвращать экземпляр IService :

services.AddTransient<Func<string, IService>>(sp => name =>
    name switch
    {
        "A" => sp.GetService<ServiceA>(),
        "B" => sp.GetService<ServiceB>(),
        _ => throw new NotImplementedException()
    });

Затем вы можете внедрить Func<string, IService> как зависимость везде, где вам нужно использовать фабрику.

Создать фабричный класс

Если вы хотите фабричный код в своем собственном классе, а не в регистрации DI, вы можете создать простой класс, который принимает экземпляр IServiceProvider.

public interface IServiceFactory
{
    IService GetService(string name);
}

public class ServiceFactory : IServiceFactory
{
    private readonly IServiceProvider _provider;

    public ServiceFactory(IServiceProvider provider)
    {
        _provider = provider;
    }

    public IService GetService(string name) =>
        name switch
        {
            "A" => _provider.GetService<ServiceA>(),
            "B" => _provider.GetService<ServiceB>(),
            _ => throw new NotImplementedException()
        };
}

. При этом вам нужно только зарегистрировать эти типы. И тогда вы можете вводить IServiceFactory по мере необходимости.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...