简体   繁体   English

根据对象类型解析服务的设计模式?

[英]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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM