首页 > 解决方案 > 如何在 javascript 中实现复杂的决策

问题描述

语境:

我们正在为注册组件编写逻辑。如果用户未通过身份验证,则应显示该表单。如果/当用户通过身份验证时,它应该重定向到几个地方之一。如果有未读消息,请重定向到第一条消息。如果没有未读消息,请重定向到仪表板。

我们还需要处理另一种情况。当有新消息到达时,用户可以收到一封电子邮件通知,其中包含指向登录表单的链接以及带有特定消息 ID 的查询参数。例如:/signin?new_message=42。在这些情况下,如果用户当前未通过身份验证,则应显示登录表单;如果/当用户通过身份验证时,重定向到该特定消息。

我的问题:

我们如何以一种优雅且可扩展的方式实现这一点?

怀疑状态机是完成这项工作的正确工具,但我对其他方法持开放态度。我强调了可扩展这个词,因为这不是代码高尔夫!我正在寻找一种现实生活中的解决方案,该解决方案可以优雅地扩展以在未来包含额外的业务逻辑。

注意:我实际上并不特别关心 javascript,但 StackOverflow 最佳实践强调特异性,而 JS 是我正在使用的语言。因此,可接受的答案可以使用伪代码,只要它在概念上与 javaScript 兼容。(不要对仅适用于 Go 的东西进行伪代码)

剧透警告!这是错误的答案:

if (authed && hasUnreadMessages && !clickFromEmail) {
  redirect = `/messages/${fistUnreadMessageId}`;
}
if (authed && !hasUnreadMessages && !clickFromEmail) {
  redirect = `/dashboard`
}
if (authed && clickFromEmail) {
  redirect = `/messages/${messageIdFromQueryString}`
}
...

^ 嵌套条件的混乱是我们试图解决的问题。

不是我的问题

这是一个真实的例子,但我的问题的主要目标是了解如何实现复杂的决策逻辑。所以我对完全避免这种逻辑的架构解决方案不感兴趣。例如:“创建不同的表单/端点来处理不同的场景”

我也对依赖特定库的解决方案不感兴趣。例如:“你应该只使用 ComplexSigninLibrary.js”

产品设计或用户体验建议也忽略了这个问题的重点,例如:“直接从电子邮件通知链接到新消息会是更好的用户体验......”

标签: javascriptdesign-patternsstate-machinefinite-automata

解决方案


您给出的上下文和示例将问题呈现为“我如何根据几个布尔值的状态做出决定”,对于这个问题,实际上不需要或不希望将事情比连续的 if 语句更复杂,可选地使用 return to避免嵌套。

这已经是干净且可读的代码,并且可能是您列出的条件的最短和最有效的实现:

if (!authed) {
  return `/auth`;
}
if(clickFromEmail) {
  return `/messages/${messageIdFromQueryString}`;
}
if(hasUnreadMessages) {
  return `/messages/${fistUnreadMessageId}`;
}
return `/dashboard`;

推荐阅读