重构为工厂方法
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
我在函数中有一个代码块。我想重构它以应用工厂模式。
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