[英]Design pattern to resolve a service by object type?
I'm trying to refactor some code that basically has a switch statement on object type and calls a specific service method based off that type. 我正在尝试重构一些基本上在对象类型上具有switch语句并基于该类型调用特定服务方法的代码。 I tried to keep the same code as basic as possible.
我试图使相同的代码尽可能地基本。
if (user is Employee)
{
_userService.DoSomething(user);
}
else if (user is Manager)
{
_managerService.DoSomething(user);
}
else if (user is Executive)
{
_executiveService.DoSomething(user);
}
I'd like to abstract the service calls to an interface and reduce the number of lines of code. 我想抽象对接口的服务调用,并减少代码行数。 My question is on the ServiceResolver part, is there a specific design pattern associated with this type of problem?
我的问题是在ServiceResolver部分上,是否存在与此类问题相关的特定设计模式? I can easily create a class that has a switch statement that returns the correct service that implements the interface but that doesn't seem as clean as I'd like it.
我可以轻松创建一个类,该类具有一个switch语句,该语句返回实现该接口的正确服务,但看起来并不像我想要的那样干净。 Any suggestions?
有什么建议么? I'm already using structure map constructor injection, could that be used with conditions or something?
我已经在使用结构映射构造函数注入,可以将其与条件一起使用吗?
public interface IUserDoSomethingService
{
void DoSomething(User user)
}
var userDoSomethingService = _userDoSomethingServiceResolver(user);
userDoSomethingService.DoSomething(user);
Simples! 简单! I am going to assume you don't need to cast (you actually have the type strongly typed).
我将假设您不需要强制转换(您实际上具有强类型键入)。
In that case you just need a Generic on IDoSomethingService 在这种情况下,您只需要IDoSomethingService上的Generic
public interface IServiceDoSomethingOn<in T>
{
void DoSomethingOn(T thing);
}
Now on the service call you just need to call... 现在,在服务电话上,您只需致电...
public void DoSomethingOnSomethingElse<T>(T thatSomething)
{
var service = ServiceResolver.Current.Resolve<IServiceDoSomethingOn<T>>();
service.DoSomethingOn(thatSomething);
}
Edit: The semi generic solution. 编辑:半通用的解决方案。 Warning I do not know how well structure map will deal with Covariance and Contravariance.
警告我不知道结构图将如何处理协方差和协方差。 So inheritance might not work.
因此继承可能行不通。
public void DoSomethingOnSomethingElse(object thatSomething, Type type)
{
var genericMethod = this.GetType().GetMethods()
.Single(x => x.IsGeneric && x.Name == "DoSomethingOnSomethingElse");
var method = genericMethod.MakeGenericMethod(type);
method.Invoke(this, new object[]{thatSomething});
}
From my view point, appropriate design pattern for your situation are strategy pattern. 我认为,适合您情况的设计模式是策略模式。 You can take reference here: http://blogs.microsoft.co.il/blogs/gilf/archive/2009/11/22/applying-strategy-pattern-instead-of-using-switch-statements.aspx .
您可以在此处参考: http : //blogs.microsoft.co.il/blogs/gilf/archive/2009/11/22/applying-strategy-pattern-instead-of-using-switch-statements.aspx 。
You can register each Type name as a key into structure map to resolve the appropriate concrete class. 您可以将每个类型名称注册为结构映射中的键,以解析适当的具体类。
Hope this help. 希望对您有所帮助。
Why not abstract factory pattern ? 为什么不抽象工厂模式 ?
public class UserServiceFactory : IUserServiceFactory {
public EmployeeServiceFactory(IUserService employeeService
, IUserService managerService
, IUserService executiveService) {
//null guards
this.employeeService = employeeService;
this.managerService = managerService;
this.executiveService = executiveService;
}
}
From here, you have 2 options, either use the traditional if-else statement or strategy pattern to resolve by object type. 在这里,您有2个选项,可以使用传统的if-else语句或策略模式来按对象类型进行解析。
If-else example (method inside UserServiceFactory): If-else示例(UserServiceFactory中的方法):
public void DoSomething(User user) {
if (user is Employee) {
employeeService.DoSomething(user);
}
else if (user is Manager) {
managerService.DoSomething(user);
}
else if (user is Executive) {
executiveService.DoSomething(user);
}
}
Resolve by object type: 按对象类型解析:
public void DoSomething(Employee user) {
employeeService.DoSomething(user);
}
public void DoSomething(Manager user) {
managerService.DoSomething(user);
}
public void DoSomething(Executive user) {
executiveService.DoSomething(user);
}
There should be another way to do it, by using naming over configuration, but I'm still incapable of doing it. 应该有另一种方法,通过在配置上使用命名,但是我仍然无能为力。
The usage in direct call: 直接调用的用法:
public void CallUser() {
// declare the services and user here
UserServiceFactory userServiceFactory = new UserServiceFactory(employeeService
, managerService
, executiveService);
userServiceFactory.DoSomething(user);
}
The usage in other service , inject the factory instead of the service collection. 其他服务中的用法 ,注入工厂而不是服务集合。
public class UserServiceConsumer:IUserServiceConsumer {
public UserServiceConsumer(IUserServiceFactory userServiceFactory) {
this.userServiceFactory = userServiceFactory;
}
IUserServiceFactory userServiceFactory;
public void ConsumeFactory(User user) {
//do some validation maybe
userServiceFactory.DoSomething(user);
}
}
It may sound complicated, but simple enough after you understand it. 听起来可能很复杂,但在您理解之后就足够简单了。
My idea is: 我的想法是:
public interface IUserDoSomethingService {
void DoSomething(Employee user);
void DoSomething(Manager user);
void DoSomething(Executive user);
}
You can also use Managed Extensibility Framework (MEF) , which is part of System.ComponentModel.Composition
namespace in .Net and can be used in conjunction with ServiceLocator
pattern. 您还可以使用Managed Extensibility Framework (MEF) ,它是.Net中
System.ComponentModel.Composition
命名空间的一部分,可以与ServiceLocator
模式结合使用。 Here are some articles
on MEF: 以下是有关MEF的一些
articles
:
http://fernandomachadopirizen.wordpress.com/2010/04/19/a-simple-introduction-to-the-microsoft-extensibility-framework/ http://fernandomachadopirizen.wordpress.com/2010/04/19/a-simple-introduction-to-the-microsoft-extensibility-framework/
http://msdn.microsoft.com/en-IN/library/dd460648(v=vs.100).aspx http://msdn.microsoft.com/zh-CN/library/dd460648(v=vs.100).aspx
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.