2

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

原始索引方法:

  • IsUserEnrolled <-- WCF 调用
    • 如果没有注册
      • 如果用户可以注册,则运行规则 <-- WCF 调用
        • 如果用户无效重定向到 No Access
        • 如果用户有效注册重定向注册
    • 如果用户已注册
      • 获取项目<-- WCF 调用
      • 显示索引页面

对后端 Web 服务的三个 wcf 调用

随着新增内容,我需要一些新信息,一些用户选项。

  • IsUserEnrolled <-- WCF 调用
    • 如果没有注册
      • 如果用户可以注册,则运行规则<-- WCF 调用
        • 如果用户无效重定向到 No Access
        • 如果用户有效注册重定向注册
    • 如果用户已注册
      • 获取项目<-- WCF 调用
      • 获取用户选项<-- WCF 调用
      • 显示索引页面

这个特性导致了一个新的 WCF 调用,这使得这个方法有 4 次在线调用。一定有更好的方法。

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

  • 获取用户信息(简称结果对象)<--WCF调用
    • 如果不是结果。IsEnrolled
      • 如果 result.RulesResult.UserIsValid 属性为 false
        • 重定向到禁止访问
      • 如果该属性为真
        • 重定向到注册
    • 如果结果.IsEnrolled
      • 使用 result.UserOptions 和 result.Items 填充 ViewModel

我们只有一个好的电话,但是我的问题

  • 结果,拥有一个对象有意义吗?

  • 如果 IsEnrolled 为 true,则 RulesResult 将为 null,在这种情况下使用 null 属性是否有意义?也许提供一个结果,该结果还表明用户已注册,以防以后对其进行检查?

  • 如果 IsEnrolled 为 false,则将填充 RulesResult(有意义)但是 Items 将为 null(有点有意义)用户选项也将为 null 在这种情况下,拥有一个空的项目列表和用户选项是否比 null 更有意义?

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

两个版本的代码示例:
版本 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);
    }
}
4

1 回答 1

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 方法的爆炸式增长。

于 2012-07-10T21:59:51.120 回答