常见模式¶
Workflow 代码中有很多关联/泛型类型 – 这并不意味着你总是需要使用所有这些类型。以下是一些我们见到过的常见配置。
无状态 Workflows¶
请记住,workflow 状态由公共部分和私有部分组成。当 workflow 的状态完全由公共状态组成时(例如 Swift 中的初始化参数或 Kotlin 中的 PropsT
),它可以忽略所有用于私有状态的机制。在 Swift 中,State
类型可以是 Void
,在 Kotlin 中可以是 Unit
– 这类 workflow 通常被称为“无状态”,因为它们没有自己的状态。
无 Props Workflows¶
有些 workflow 完全在内部管理其所有状态,并且没有公共状态(即 props)。在 Swift 中,这仅意味着 workflow 实现没有参数(尽管这种情况很少见,请参阅下面的 注入依赖)。在 Kotlin 中,PropsT
类型可以是 Unit
。RenderContext
为这些 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
/Nothing
的 Output
。
想象一个 PromptForPermissionMaybeWorkflow
,它渲染一个 UI 来获取密码,但仅在权限尚未授予的情况下。如果你将其 RenderingT
设置为可空类型(例如 Screen?
),它可以返回 null
来指示其任务已完成。其调用者将同步得知障碍已清除,并可以立即渲染他们真正关心的内容。
此模式的另一种变体是为 Rendering
使用密封类/枚举类型,其中包含实现 Screen
的 Working
类型,以及携带工作成果的不可见的 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 有属性,它们应该只用于存储注入的依赖或从注入的依赖派生的依赖(例如从 Observable
s 创建的 Worker
s)。
注意
Swift 和 Kotlin 实践之间的这种差异是 Kotlin 缺乏类似于 Swift 的 Self
类型所带来的副作用。Kotlin 没有实用的方法来提供类似于 Swift 的 Workflow.workflowDidChange
方法,该方法接受一个强类型引用,指向父 workflow Render
方法前一次运行的实例。Kotlin 的替代方法 StatefulWorkflow.onPropsChanged
需要额外的 PropsT
类型参数。