跳到内容

常见模式

Workflow 代码中有很多关联/泛型类型 – 这并不意味着你总是需要使用所有这些类型。以下是一些我们见到过的常见配置。

无状态 Workflows

请记住,workflow 状态由公共部分和私有部分组成。当 workflow 的状态完全由公共状态组成时(例如 Swift 中的初始化参数或 Kotlin 中的 PropsT),它可以忽略所有用于私有状态的机制。在 Swift 中,State 类型可以是 Void,在 Kotlin 中可以是 Unit – 这类 workflow 通常被称为“无状态”,因为它们没有自己的状态。

无 Props Workflows

有些 workflow 完全在内部管理其所有状态,并且没有公共状态(即 props)。在 Swift 中,这仅意味着 workflow 实现没有参数(尽管这种情况很少见,请参阅下面的 注入依赖)。在 Kotlin 中,PropsT 类型可以是 UnitRenderContext 为这些 workflow 提供了其大多数函数的便捷重载,以便隐式传递 Unit

无 Output Workflows

仅通过其 Rendering 与其父 workflow 通信,并且从不发出任何 output 的 workflow,建议使用 底部类型 作为其 Output 类型来表明这一点。除了记录 workflow 永远不会输出的事实之外,使用底部类型还可以让编译器强制执行此规则 – 尝试发出 output 的代码将无法编译。在 Swift 中,Output 类型被指定为 Never。在 Kotlin 中,使用 Nothing

组合 Workflows

组合是使用 Workflows 的强大工具。一个 workflow 通常只需渲染各种子 workflow 即可完成很多工作。它可以简单地组合多个子 workflow 的渲染结果,或者使用其 props 来确定渲染哪一组子 workflow。这类 workflow 通常可以是无状态的。

一次性 Workflows (RenderingT 对比 OutputT)

一个常见的问题是“为什么我不能从 initialState 发出 output”,或者“如果我的 Workflow 发现它实际上不需要运行怎么办?处理这种情况最有效、最具表达力的方式是使用可选或条件 Rendering 类型,以及 Never/NothingOutput

想象一个 PromptForPermissionMaybeWorkflow,它渲染一个 UI 来获取密码,但仅在权限尚未授予的情况下。如果你将其 RenderingT 设置为可空类型(例如 Screen?),它可以返回 null 来指示其任务已完成。其调用者将同步得知障碍已清除,并可以立即渲染他们真正关心的内容。

此模式的另一种变体是为 Rendering 使用密封类/枚举类型,其中包含实现 ScreenWorking 类型,以及携带工作成果的不可见的 Finished 类型。

在选择使用 Rendering 还是 Output 时,一个好的经验法则是记住 Output 类似事件,并且总是异步的。等待 output 的父 workflow 在此期间必须有东西可供渲染。对于负责提供单一产品(尤其是可能立即可用的产品)的一次性 workflow 来说,使用 Rendering 是一个很好的习惯用法。

Props 值 对比 注入的依赖

依赖注入 是一种使代码耦合度更低、更易于测试的技术。简而言之,类/结构体最好在创建时接受它们的依赖,而不是硬编码它们。Workflows 通常具有依赖项,例如执行某些任务所需的特定 Workers、委托渲染的子 workflows,或用于网络请求、格式化和日志记录等方面的助手。

Swift

Swift workflow 通常将其依赖作为初始化参数接收,就像其输入值一样,并且通常由其父 workflow 在每次调用父 workflow 的渲染方法时重新实例化。可以使用工厂模式来防止子 workflow 的实现细节泄露到其父 workflow 中。

Kotlin

Kotlin workflow 通过 Kotlin Workflow 接口上的 PropsT 参数类型,对依赖和 props 进行了更正式的区分。依赖(例如网络服务)通常作为构造函数参数提供,而 props 值(例如记录定位器)由父 workflow 作为参数提供给 RenderContext.renderChild 方法。这与 Dagger 等 DI 库无缝协作。

细心的读者会注意到,这在技术上是在 workflow 实例中存储“状态”——这通常是不推荐的。然而,由于这种“状态”从不改变,我们可以为此情况破例。如果 workflow 有属性,它们应该用于存储注入的依赖或从注入的依赖派生的依赖(例如从 Observables 创建的 Workers)。

注意

Swift 和 Kotlin 实践之间的这种差异是 Kotlin 缺乏类似于 Swift 的 Self 类型所带来的副作用。Kotlin 没有实用的方法来提供类似于 Swift 的 Workflow.workflowDidChange 方法,该方法接受一个强类型引用,指向父 workflow Render 方法前一次运行的实例。Kotlin 的替代方法 StatefulWorkflow.onPropsChanged 需要额外的 PropsT 类型参数。