2012-07-10 51 views
2

我不得不最近向我写的现有应用程序添加一项新功能,并查看代码的这一部分意识到它可能是重构和改进的时候了。重构WCF服务

原始指数法:

  • IsUserEnrolled < - WCF呼叫
    • 如果未注册
      • 运行规则,如果用户可以注册< - WCF呼叫
        • 如果用户无效,重定向到无Acc ESS
        • 如果用户是有效的登记重定向到注册
    • 如果用户登记
      • 获取项目< - WCF呼叫
      • 显示索引页

三个wcf调用后端Web服务

随着新的添加,我需要一些新的信息,一些用户选项。

  • IsUserEnrolled < - WCF呼叫
    • 如果未注册
      • 运行规则,如果用户可以注册< - WCF呼叫
        • 如果用户是无效重定向没有访问
        • 如果用户有效注册重定向到注册
    • 如果用户登记
      • 获取项目< - WCF呼叫
      • 获取用户选项< - WCF呼叫
      • 显示索引页

此功能导致了一个新的WCF呼叫,使这一个方法有4个呼叫通过电线。一定有更好的方法。

我的建议是将其封装到一个wcf调用中,以收集有关用户的所有信息,他们是否注册,项目,如果需要运行规则以及用户选项。

  • 获取用户信息(简称结果对象)< --WCF呼叫
    • 如果没有result.IsEnrolled
      • 如果result.RulesResult.UserIsValid属性为false
        • 重定向无访问
      • 如果该属性为真
        • 重定向到注册
    • 如果result.IsEnrolled
      • 与result.UserOptions和result.Items

填充视图模型我们只有一个电话t是不错的,但是我的问题

  • 是否有一个对象是有意义的结果?

  • 如果IsEnrolled为true,则RulesResult将为null,在此实例中是否有null属性有意义?也许提供一个结果,也表示用户注册了之后再进行检查?

  • 如果IsEnrolled为false,则将会填充RulesResult(有意义),但是项目将为空(有意义)用户选项也将为空 在这种情况下,具有项目和用户选项的空列表使更有意义然后null?

  • 从api设计的角度来看,第二种选择是否有意义,或者是与UI密切相关的结果?

代码例如两个verions:
版本1:

public ActionResult Index() 
{ 

    using (var client =ServiceFactory.CreateChannel()) 
    { 
     var isMemberEnrolled = client.IsMemberEnrolled(User.Identity.Name); 

     if (!isMemberEnrolled) 
     { 
      var accessResult = client.RunRules(User.Identity.Name); 

      if (!accessResult.UserIsValid) 
      { 
       return RedirectToAction("NoAccess"); 
      } 
      return RedirectToAction("Register"); 
     } 

     var userOptions = client.GetUserOptions(User.Identity.Name); 

     List<Item> items = client.GetUserItems(User.Identity.Name); 

     var viewModel = new ViewModel(userOptions, items); 

     return View(viewModel); 
    } 
} 

2版(重构):

public ActionResult Index() 
{ 

    using (var client = ServiceFactory.CreateChannel()) 
    { 
     var userInformation = client.GetUserInformation(User.Identity.Name); 

     if (!userInformation.IsMemberEnrolled) 
     { 
      return RedirectToAction(!userInformation.RulesResult.UserIsValid ? "NoAccess" : "Register"); 
     } 

     var viewModel = new ViewModel(userInformation.UserOptions, userInformation.Items); 

     return View(viewModel); 
    } 
} 

回答

2

我认为对于API效率,选项# 2肯定会表现更好。只要在一个结果对象中具有全部未使用的参数,就可以很容易地用抽象结果类来解决,然后将两个不同的响应分成两个不同的具体子类型。

[KnownType(typeof(UserInfoEnrolledResult))] 
    [KnownType(typeof(UserInfoNotEnrolledResult))] 
    [DataContract] 
    public abstract class UserInfoResult 
    { 
    } 

    [DataContract] 
    public class UserInfoEnrolledResult : UserInfoResult 
    { 
    [DataMember] 
    public string UserOptions { get; set; } 

    [DataMember] 
    public string[] Items { get; set; } 
    } 

    [DataContract] 
    class UserInfoNotEnrolledResult : UserInfoResult 
    { 
    [DataMember] 
    public bool UserIsValid { get; set; } 
    } 

那么你的客户端代码将成为像...

using (var client = ServiceFactory.CreateChannel()) 
    { 
    var userInformation = client.GetUserInformation(User.Identity.Name); 

    if (userInformation is UserInfoNotEnrolledResult) 
    { 
     return RedirectToAction(((UserInfoNotEnrolledResult)userInformation).UserIsValid ? "NoAccess" : "Register"); 
    } 

    var enrolledUserInformation = (UserInfoEnrolledResult)userInformation; 

    var viewModel = new ViewModel(enrolledUserInformation.UserOptions, enrolledUserInformation.Items); 

    return View(viewModel); 
    } 

这清楚地向客户端两种不同的反应是可能的,并保持它明确其使用或需要的参数什么样的回应。

我认为这是一个非常好的方式。如果你开始跨情况下,当你发现自己创造了许多不同种类的,其与像微小的差别都大致相同功能的步骤,然后运行...

UserInfoResult GetUserInformation(string name); 
UserInfoResult GetUserInformationWithoutRuleCheck(string name); 
UserInfoResult GetUserInformationWithDoubleSecretChecks(string name); 

,它可能是值得的,它们分解大功能分成多个WCF调用以确保您没有爆炸性的API方法。

+0

我确实喜欢抽象结果的想法,调用者非常清楚不同的结果是可能的。 – 2012-07-10 23:06:38