移动开发 - Router组件

移动开发 - Router组件_第1张图片
MVVM+Router

在移动开发中讨论到Router的时候,一般直接想到的样式是这样子:

//iOS
//注册
Router.map("myapp://user/", UserViewController.self)
//调用
Router.push("myapp://user/123")
Router.present("myapp://post/54321", wrap: true)

//Android
//注册
@Router("user/:userId")
public class UserActivity extends Activity {
    ...
}
//调用
ARouter.getInstance().build("/user/9527")
            .withInt("age", 23)
            .navigation();

引入Router后,页面/组件之间的跳转依赖于路由,可以降低其之间的耦合度。且、若应用支持推送或外部链接的时候,Router还可以让跳转到指定页面逻辑的逻辑复用,降低维护成本。

移动开发 - Router组件_第2张图片

细心的读者会发现,上述Router只是解决了如何跳转的问题,而决定跳转到哪个页面的逻辑依然在Controller或Activity内,这明显违反了功能单一的设计原则,我们可以扩展下Router ,把决定跳转的业务逻辑放置在Router内。

移动开发 - Router组件_第3张图片

上图的例子中可以看到三个Route:

  • Sign In > 首页
  • Get a Free Apple ID > 注册页面
  • Forgot Apple ID or Password ? > 忘记密码页面

因为用户登录时有可能失败(密码忘记了?),这就多出现一个Route:

  • Sign In > 首页 或 忘记密码页面

面临这个场景, 我们可以在Controller里实现以下逻辑:

func loginButtonTapped() {
   if shouldChangePassword {
      Router.push("myapp://login/changepwd")
   } else {
      Router.push("myapp://user/home")
   }
}

上面代码中的逻辑判断不应属于Controller,Controller内只应包括View相关的或系统的事件回调处理。这时我们可以引进LoginRouter了。

class LoginRouter {
   func route(
      to routeID: String, 
      from context: UIViewController, 
      parameters: Any?) 
   {
      guard let route = LoginVC.Route(rawValue: routeID) else {
         return
      }
      switch route {
      case .login:
         if shouldChangePassword {
              Router.push("myapp://login/changepwd")
         } else {
              Router.push("myapp://user/home")
         }
      case .signUp:
         Router.push("myapp://login/signup")
      case . forgotPasswordScreen:
         Router.push("myapp://login/changepwd")
      }
   }
}

这样在原来的Controller内代码也要做相应修改,注意这里省略了登录状态的传递,如果是MVVM结构可以使用ViewModel, Redux 模式可传递State。具体可iOS 常见架构一览。

class LoginViewController: UIViewController {
   enum Route: String {
      case login
      case signUp
      case forgotPassword
   }
   var router: LoginRouter!
   ...
   func loginButtonTapped() {
      router.route(to: Route.login.rawValue, from: self)
   }
   func signUpTapped() {
      router.route(to: Route.signUp.rawValue, from: self)
   }
   func forgotPasswordTapped() {
      router.route(to: Route.forgotPassword.rawValue, from: self)
   }

这样我们完全把路由相关代码完全从Controller移出,将来需若改变路由代码,只需修改路由类即可,而不用到处搜索相应的View Controller。

同时我们也完成了Controller的瘦身目标,有兴趣的可以阅读iOS - Controller 瘦身简析。

更多

获取更多内容请关注微信公众号豆志昂扬:

  • 直接添加公众号豆志昂扬
  • 微信扫描下图二维码;
移动开发 - Router组件_第4张图片

你可能感兴趣的:(移动开发 - Router组件)