重构为工厂方法

Refactoring to factory method

我在函数中有一个代码块。我想重构它以应用工厂模式。

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

所以我担心的是,它仍然是工厂模式吗?如果不是,如何将其重构为工厂模式?

而且我到处都在阅读,工厂模式和依赖注入做同样的工作。如何实现我的依赖注入代码?

您目前使用 ServiceFactory 的方法本质上是一个抽象工厂,因为您将相关对象集的创建封装在一个方法后面。

有几种不同的方法可以通过依赖注入获得类似的结果。这样做的主要好处之一是您不再需要手动构建任何服务 classes。以下是一些使用 .NET Core DI 框架的示例:

注册工厂代表

您可以注册 Func<string, IService>,它将接受一个字符串和 return IService:

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

然后您可以在需要使用工厂的任何地方将 Func<string, IService> 作为依赖项注入。

创建工厂class

如果你想要工厂代码在它自己的 class 中而不是在 DI 注册中,你可以创建一个简单的 class 来获取 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

重构代码的类型为:简单工厂或静态工厂。如果你有多个工厂,那就是工厂模式。也就是说,Say,ServiceFactory 和 ServiceFactory2 也 returns 一些 IService

如果您已经知道如何在自身之前构造参数(路径、日志、映射配置),那么您应该坚持使用当前的 SimpleFactory 模式本身。如果参数对象及其状态是动态的,依赖注入对我来说更有意义

您可以为服务工厂创建一个接口并实现它,而不是使用静态方法。使用接口允许您在任何 class 中注入此依赖项并模拟它以进行单元测试

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
    }
}

您可以创建某种映射 Dictionary<string, Func<ILogger, IConfig, IService>>,而不是 switch 语句和多个 case 标签,它包含服务密钥和 Func<ILogger, IConfig, IService> 委托来创建一个具体 Service。在 CreateService 方法中,您正在检查字典中是否存在服务密钥,并调用 Func 委托给 return 一个具体的服务实例,否则 return null