摘要:组合优先(Composition over Inheritance)是现代声明式UI框架的核心范式,也是 Jetpack Compose、Flutter、SwiftUI 的统一底层设计逻辑。国内开发者往往熟练掌握框架语法,却难以真正吃透「弃继承、用组合」的底层思维。本文以汉字造字原理为认知跳板,依托「有限原子,组合生繁」的通用系统规律,类比迁移、逐层拆解声明式UI的组件组合思想。通过对比传统继承式UI的固有缺陷,系统讲解原子化设计、树形组件结构、Modifier链式能力组合、状态分层架构等核心机制,横向对比三大主流声明式框架的设计共识,最终归纳组合优先范式的工程价值,帮助开发者建立标准、通透、统一的声明式UI底层思维。
关键词:组合优先;声明式UI;Jetpack Compose;Flutter;组件设计;汉字造字;软件工程架构
目录
- 一、前言
- 二、传统继承范式:单体叠加的工程缺陷
- 三、组合优先核心思想:由汉字造字迁移UI思维
- 四、原子化设计:组合体系的底层基石
- 五、树形嵌套:声明式UI的结构化组合体系
- 六、Modifier链式组合:细粒度能力的可插拔组合
- 七、状态分层架构:无状态优先的纯净组合模型
- [八、跨框架横向辨析:Flutter / Compose / SwiftUI 统一设计准则](#八、跨框架横向辨析:Flutter / Compose / SwiftUI 统一设计准则)
- 九、组合优先范式的七大核心工程收益
- 十、思维异同梳理:汉字造字与UI组件组合
- 十一、结语
一、前言
构建任意一套复杂系统,底层架构思路永远只有两种:纵向继承叠加与横向单元组合。
传统 Android View 体系采用的是继承叠加思维。通过不断继承父类、重写方法、叠加逻辑实现控件拓展,随着项目迭代深度增加,继承链条冗长、组件高度耦合、权责边界混乱。微小改动即可引发连锁报错,代码臃肿腐化、维护成本持续攀升,是典型的增量式单体弊端。
与之相对,现代移动端、前端领域全面统一的组合优先思想,重塑了传统UI开发逻辑。它是西方软件工程沉淀出的经典架构范式,也是所有声明式UI框架的设计内核。
国内开发者在学习 Compose、Flutter 时,普遍存在一个认知断层:会写组件、会拼页面,但始终不理解为什么要拆分原子、为什么禁止业务继承、为什么组合优于叠加。
为解决这一思维壁垒,本文采用最适配国人认知的学习路径:以汉字造字原理为底层类比模型,把抽象、西式的软件工程范式,转化为我们自幼熟悉的逻辑体系,从已知迁移未知,读懂声明式UI的组合本质。
汉字系统的核心原理可先概括为一句话:有限原子,组合生万物。
本文将依托该统一模型,结合 Jetpack Compose 与 Flutter 双框架可运行代码,系统拆解组合优先范式的全部核心机制,帮助开发者告别语法式学习,建立真正的底层架构思维。
二、传统继承范式:单体叠加的工程缺陷
继承式UI开发,本质是对原有单体进行改造、覆写、叠加。
Android View 体系层级固定:
text
Object → View → TextView → Button → 自定义控件
所有新增功能、样式拓展、交互变更,全部依赖子类继承实现。
传统继承式自定义控件(Java)
java
public class IconTextButton extends Button {
private Drawable icon;
public IconTextButton(Context context) {
super(context);
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
}
public void setIcon(Drawable icon) {
this.icon = icon;
}
}
该模式存在四大不可逆工程缺陷:
- 高度耦合:子类强依赖父类内部实现,父类变更极易引发隐性崩溃;
- 职责混杂:单一控件同时承担绘制、布局、状态、交互、业务逻辑,不符合单一职责;
- 变体爆炸:样式、功能稍有差异,必须新增子类,工程类文件无限膨胀;
- 刷新低效:视图与状态强绑定,无法局部刷新,只能全局重绘,性能冗余严重。
继承的本质是改造旧单体,越迭代越腐化。这也是官方从 View 体系全面转向声明式组合架构的根本原因。
下图直观对比了两种范式的结构差异:
#mermaid-svg-eoVUIigKcExjOyHQ{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-eoVUIigKcExjOyHQ .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-eoVUIigKcExjOyHQ .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-eoVUIigKcExjOyHQ .error-icon{fill:#552222;}#mermaid-svg-eoVUIigKcExjOyHQ .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-eoVUIigKcExjOyHQ .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-eoVUIigKcExjOyHQ .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-eoVUIigKcExjOyHQ .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-eoVUIigKcExjOyHQ .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-eoVUIigKcExjOyHQ .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-eoVUIigKcExjOyHQ .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-eoVUIigKcExjOyHQ .marker{fill:#333333;stroke:#333333;}#mermaid-svg-eoVUIigKcExjOyHQ .marker.cross{stroke:#333333;}#mermaid-svg-eoVUIigKcExjOyHQ svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-eoVUIigKcExjOyHQ p{margin:0;}#mermaid-svg-eoVUIigKcExjOyHQ .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-eoVUIigKcExjOyHQ .cluster-label text{fill:#333;}#mermaid-svg-eoVUIigKcExjOyHQ .cluster-label span{color:#333;}#mermaid-svg-eoVUIigKcExjOyHQ .cluster-label span p{background-color:transparent;}#mermaid-svg-eoVUIigKcExjOyHQ .label text,#mermaid-svg-eoVUIigKcExjOyHQ span{fill:#333;color:#333;}#mermaid-svg-eoVUIigKcExjOyHQ .node rect,#mermaid-svg-eoVUIigKcExjOyHQ .node circle,#mermaid-svg-eoVUIigKcExjOyHQ .node ellipse,#mermaid-svg-eoVUIigKcExjOyHQ .node polygon,#mermaid-svg-eoVUIigKcExjOyHQ .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-eoVUIigKcExjOyHQ .rough-node .label text,#mermaid-svg-eoVUIigKcExjOyHQ .node .label text,#mermaid-svg-eoVUIigKcExjOyHQ .image-shape .label,#mermaid-svg-eoVUIigKcExjOyHQ .icon-shape .label{text-anchor:middle;}#mermaid-svg-eoVUIigKcExjOyHQ .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-eoVUIigKcExjOyHQ .rough-node .label,#mermaid-svg-eoVUIigKcExjOyHQ .node .label,#mermaid-svg-eoVUIigKcExjOyHQ .image-shape .label,#mermaid-svg-eoVUIigKcExjOyHQ .icon-shape .label{text-align:center;}#mermaid-svg-eoVUIigKcExjOyHQ .node.clickable{cursor:pointer;}#mermaid-svg-eoVUIigKcExjOyHQ .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-eoVUIigKcExjOyHQ .arrowheadPath{fill:#333333;}#mermaid-svg-eoVUIigKcExjOyHQ .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-eoVUIigKcExjOyHQ .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-eoVUIigKcExjOyHQ .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-eoVUIigKcExjOyHQ .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-eoVUIigKcExjOyHQ .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-eoVUIigKcExjOyHQ .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-eoVUIigKcExjOyHQ .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-eoVUIigKcExjOyHQ .cluster text{fill:#333;}#mermaid-svg-eoVUIigKcExjOyHQ .cluster span{color:#333;}#mermaid-svg-eoVUIigKcExjOyHQ div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-eoVUIigKcExjOyHQ .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-eoVUIigKcExjOyHQ rect.text{fill:none;stroke-width:0;}#mermaid-svg-eoVUIigKcExjOyHQ .icon-shape,#mermaid-svg-eoVUIigKcExjOyHQ .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-eoVUIigKcExjOyHQ .icon-shape p,#mermaid-svg-eoVUIigKcExjOyHQ .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-eoVUIigKcExjOyHQ .icon-shape .label rect,#mermaid-svg-eoVUIigKcExjOyHQ .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-eoVUIigKcExjOyHQ .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-eoVUIigKcExjOyHQ .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-eoVUIigKcExjOyHQ :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 组合优先范式
基础原子 Text / Icon / Row
业务组件 IconTextButton
页面模块 InfoCard
完整页面 DemoPage
继承叠加范式
Object
View
TextView
Button
自定义控件
三、组合优先核心思想:由汉字造字迁移UI思维
(一)汉字造字的系统逻辑
汉字体系的高效与稳定,依托三条底层规则:
- 原子固化:偏旁部首数量有限、长期稳定、不随意变更;
- 职责单一:每个字根形态、语义、功能独立纯粹;
- 组合生繁:不创造新原子,仅通过搭配重组,生成全新汉字与语义。
「氵」+「可」为「河」,「氵」+「胡」为「湖」。原子不变,结构一变,能力全新。
汉字造字与 UI 组件组合的映射关系如下:
#mermaid-svg-NqHkLuAmztDnlnjC{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-NqHkLuAmztDnlnjC .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-NqHkLuAmztDnlnjC .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-NqHkLuAmztDnlnjC .error-icon{fill:#552222;}#mermaid-svg-NqHkLuAmztDnlnjC .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-NqHkLuAmztDnlnjC .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-NqHkLuAmztDnlnjC .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-NqHkLuAmztDnlnjC .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-NqHkLuAmztDnlnjC .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-NqHkLuAmztDnlnjC .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-NqHkLuAmztDnlnjC .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-NqHkLuAmztDnlnjC .marker{fill:#333333;stroke:#333333;}#mermaid-svg-NqHkLuAmztDnlnjC .marker.cross{stroke:#333333;}#mermaid-svg-NqHkLuAmztDnlnjC svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-NqHkLuAmztDnlnjC p{margin:0;}#mermaid-svg-NqHkLuAmztDnlnjC .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-NqHkLuAmztDnlnjC .cluster-label text{fill:#333;}#mermaid-svg-NqHkLuAmztDnlnjC .cluster-label span{color:#333;}#mermaid-svg-NqHkLuAmztDnlnjC .cluster-label span p{background-color:transparent;}#mermaid-svg-NqHkLuAmztDnlnjC .label text,#mermaid-svg-NqHkLuAmztDnlnjC span{fill:#333;color:#333;}#mermaid-svg-NqHkLuAmztDnlnjC .node rect,#mermaid-svg-NqHkLuAmztDnlnjC .node circle,#mermaid-svg-NqHkLuAmztDnlnjC .node ellipse,#mermaid-svg-NqHkLuAmztDnlnjC .node polygon,#mermaid-svg-NqHkLuAmztDnlnjC .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-NqHkLuAmztDnlnjC .rough-node .label text,#mermaid-svg-NqHkLuAmztDnlnjC .node .label text,#mermaid-svg-NqHkLuAmztDnlnjC .image-shape .label,#mermaid-svg-NqHkLuAmztDnlnjC .icon-shape .label{text-anchor:middle;}#mermaid-svg-NqHkLuAmztDnlnjC .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-NqHkLuAmztDnlnjC .rough-node .label,#mermaid-svg-NqHkLuAmztDnlnjC .node .label,#mermaid-svg-NqHkLuAmztDnlnjC .image-shape .label,#mermaid-svg-NqHkLuAmztDnlnjC .icon-shape .label{text-align:center;}#mermaid-svg-NqHkLuAmztDnlnjC .node.clickable{cursor:pointer;}#mermaid-svg-NqHkLuAmztDnlnjC .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-NqHkLuAmztDnlnjC .arrowheadPath{fill:#333333;}#mermaid-svg-NqHkLuAmztDnlnjC .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-NqHkLuAmztDnlnjC .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-NqHkLuAmztDnlnjC .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-NqHkLuAmztDnlnjC .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-NqHkLuAmztDnlnjC .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-NqHkLuAmztDnlnjC .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-NqHkLuAmztDnlnjC .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-NqHkLuAmztDnlnjC .cluster text{fill:#333;}#mermaid-svg-NqHkLuAmztDnlnjC .cluster span{color:#333;}#mermaid-svg-NqHkLuAmztDnlnjC div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-NqHkLuAmztDnlnjC .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-NqHkLuAmztDnlnjC rect.text{fill:none;stroke-width:0;}#mermaid-svg-NqHkLuAmztDnlnjC .icon-shape,#mermaid-svg-NqHkLuAmztDnlnjC .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-NqHkLuAmztDnlnjC .icon-shape p,#mermaid-svg-NqHkLuAmztDnlnjC .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-NqHkLuAmztDnlnjC .icon-shape .label rect,#mermaid-svg-NqHkLuAmztDnlnjC .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-NqHkLuAmztDnlnjC .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-NqHkLuAmztDnlnjC .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-NqHkLuAmztDnlnjC :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 有限原子,组合生万物
汉字造字体系
声明式UI体系
偏旁部首:氵 / 可 / 胡
组合生成:河 / 湖
基础组件:Text / Icon / Row
组合生成:IconTextButton / InfoCard
(二)声明式UI的对等架构逻辑
声明式UI完全复刻上述思想:
- 组件原子固化:Text、Row、Column、Button 为系统基础单元;
- 原子职责单一:每个组件只负责一件事,互不侵入、互不干扰;
- 业务全靠组合:不修改底层源码,不继承拓展,仅通过嵌套、传参、排布生成复杂UI。
Compose 标准组合式控件实现(零继承)
kotlin
@Composable
fun IconTextButton(
text: String,
painter: Painter,
onClick: () -> Unit
) {
Button(onClick = onClick) {
Row(
horizontalArrangement = Arrangement.spacedBy(6.dp),
verticalAlignment = Alignment.CenterVertically
) {
Icon(
painter = painter,
contentDescription = null,
modifier = Modifier.size(18.dp)
)
Text(text = text)
}
}
}
完全贴合汉字造字逻辑:底层原子恒定,所有业务能力、形态差异、复杂界面,全部来自组合关系的变化。
组合优先范式标准定义:不修改底层原子、不依托类继承拓展能力;所有业务复杂度、界面形态、功能叠加,均通过组件嵌套、参数配置、回调组合实现。系统底层封闭稳定,所有变化承载于组合结构之上。
四、原子化设计:组合体系的底层基石
无论是汉字系统,还是现代UI架构,体系可拓展的前提,是原子足够纯粹。
Compose 原生基础组件全部满足最小不可拆分、职责绝对单一:
- Text:仅文本渲染;
- Icon / Image:仅图形展示;
- Row / Column / Box:仅布局排布;
- Button:仅封装点击交互;
- TextField:仅文本输入捕获。
复杂界面禁止修改底层组件源码,只允许上层拼装组合。
原子拼装业务模块示例
kotlin
@Composable
fun InfoCard(title: String, desc: String) {
Card(
modifier = Modifier.fillMaxWidth(),
elevation = CardDefaults.cardElevation(defaultElevation = 4.dp)
) {
Column(modifier = Modifier.padding(16.dp)) {
Text(text = title, style = MaterialTheme.typography.titleMedium)
Spacer(modifier = Modifier.height(8.dp))
Text(text = desc, style = MaterialTheme.typography.bodyMedium)
}
}
}
通过少量基础原子的自由组合,即可实现无限多业务形态。原子恒常,变化生于组合之间。
五、树形嵌套:声明式UI的结构化组合体系
汉字组合是静态固定结构,成型后不可变更;声明式UI组合是动态可计算组件树,具备响应式更新能力。
页面结构层级清晰:
- 根节点:页面容器 Scaffold;
- 中层节点:自定义业务组件、模块卡片;
- 叶子节点:基础渲染原子。
嵌套顺序严格对应视觉结构,结构即界面。
组件树的层级结构可以表示为:
#mermaid-svg-Qrvnk7ERbPF2BtT4{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-Qrvnk7ERbPF2BtT4 .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-Qrvnk7ERbPF2BtT4 .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-Qrvnk7ERbPF2BtT4 .error-icon{fill:#552222;}#mermaid-svg-Qrvnk7ERbPF2BtT4 .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-Qrvnk7ERbPF2BtT4 .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-Qrvnk7ERbPF2BtT4 .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-Qrvnk7ERbPF2BtT4 .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-Qrvnk7ERbPF2BtT4 .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-Qrvnk7ERbPF2BtT4 .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-Qrvnk7ERbPF2BtT4 .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-Qrvnk7ERbPF2BtT4 .marker{fill:#333333;stroke:#333333;}#mermaid-svg-Qrvnk7ERbPF2BtT4 .marker.cross{stroke:#333333;}#mermaid-svg-Qrvnk7ERbPF2BtT4 svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-Qrvnk7ERbPF2BtT4 p{margin:0;}#mermaid-svg-Qrvnk7ERbPF2BtT4 .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-Qrvnk7ERbPF2BtT4 .cluster-label text{fill:#333;}#mermaid-svg-Qrvnk7ERbPF2BtT4 .cluster-label span{color:#333;}#mermaid-svg-Qrvnk7ERbPF2BtT4 .cluster-label span p{background-color:transparent;}#mermaid-svg-Qrvnk7ERbPF2BtT4 .label text,#mermaid-svg-Qrvnk7ERbPF2BtT4 span{fill:#333;color:#333;}#mermaid-svg-Qrvnk7ERbPF2BtT4 .node rect,#mermaid-svg-Qrvnk7ERbPF2BtT4 .node circle,#mermaid-svg-Qrvnk7ERbPF2BtT4 .node ellipse,#mermaid-svg-Qrvnk7ERbPF2BtT4 .node polygon,#mermaid-svg-Qrvnk7ERbPF2BtT4 .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-Qrvnk7ERbPF2BtT4 .rough-node .label text,#mermaid-svg-Qrvnk7ERbPF2BtT4 .node .label text,#mermaid-svg-Qrvnk7ERbPF2BtT4 .image-shape .label,#mermaid-svg-Qrvnk7ERbPF2BtT4 .icon-shape .label{text-anchor:middle;}#mermaid-svg-Qrvnk7ERbPF2BtT4 .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-Qrvnk7ERbPF2BtT4 .rough-node .label,#mermaid-svg-Qrvnk7ERbPF2BtT4 .node .label,#mermaid-svg-Qrvnk7ERbPF2BtT4 .image-shape .label,#mermaid-svg-Qrvnk7ERbPF2BtT4 .icon-shape .label{text-align:center;}#mermaid-svg-Qrvnk7ERbPF2BtT4 .node.clickable{cursor:pointer;}#mermaid-svg-Qrvnk7ERbPF2BtT4 .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-Qrvnk7ERbPF2BtT4 .arrowheadPath{fill:#333333;}#mermaid-svg-Qrvnk7ERbPF2BtT4 .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-Qrvnk7ERbPF2BtT4 .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-Qrvnk7ERbPF2BtT4 .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-Qrvnk7ERbPF2BtT4 .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-Qrvnk7ERbPF2BtT4 .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-Qrvnk7ERbPF2BtT4 .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-Qrvnk7ERbPF2BtT4 .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-Qrvnk7ERbPF2BtT4 .cluster text{fill:#333;}#mermaid-svg-Qrvnk7ERbPF2BtT4 .cluster span{color:#333;}#mermaid-svg-Qrvnk7ERbPF2BtT4 div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-Qrvnk7ERbPF2BtT4 .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-Qrvnk7ERbPF2BtT4 rect.text{fill:none;stroke-width:0;}#mermaid-svg-Qrvnk7ERbPF2BtT4 .icon-shape,#mermaid-svg-Qrvnk7ERbPF2BtT4 .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-Qrvnk7ERbPF2BtT4 .icon-shape p,#mermaid-svg-Qrvnk7ERbPF2BtT4 .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-Qrvnk7ERbPF2BtT4 .icon-shape .label rect,#mermaid-svg-Qrvnk7ERbPF2BtT4 .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-Qrvnk7ERbPF2BtT4 .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-Qrvnk7ERbPF2BtT4 .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-Qrvnk7ERbPF2BtT4 :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 根节点:Scaffold
中层节点:InfoCard
中层节点:IconTextButton
叶子节点:Text
叶子节点:Spacer
叶子节点:Icon
叶子节点:Text
完整页面组合示例
kotlin
@Composable
fun DemoPage() {
// 示例省略 ExperimentalMaterial3Api 注解
Scaffold(
topBar = { TopAppBar(title = { Text("组合范式演示") }) }
) { innerPadding ->
Column(
modifier = Modifier
.fillMaxSize()
.padding(innerPadding)
.padding(16.dp),
verticalArrangement = Arrangement.spacedBy(12.dp)
) {
InfoCard(
title = "标题示例",
desc = "通过原子组合生成业务模块"
)
IconTextButton(
text = "提交",
painter = painterResource(R.drawable.ic_send)
) {}
}
}
}
依托 Compose 快照状态机制,仅更新状态依赖的最小组件分支,实现精准局部刷新。这是静态汉字组合不具备的动态工程能力。
六、Modifier链式组合:细粒度能力的可插拔组合
汉字仅存在结构组合;声明式UI进一步实现了能力层组合。
布局、边距、背景、圆角、点击、阴影,全部拆分为独立修饰原子,支持链式叠加、自由排序、动态插拔。
kotlin
// 先边距、后背景:背景不包含边距区域
Text(
"示例文字",
modifier = Modifier
.padding(12.dp)
.background(Color.LightGray, RoundedCornerShape(8.dp))
)
// 先背景、后边距:背景包裹全部区域
Text(
"示例文字",
modifier = Modifier
.background(Color.LightGray, RoundedCornerShape(8.dp))
.padding(12.dp)
)
组件本体无任何变更,仅调整能力原子的组合顺序,即可产出完全不同的视觉效果。能力正交、顺序即语义,这是现代UI架构解耦、可拓展、高灵活的核心关键。
七、状态分层架构:无状态优先的纯净组合模型
声明式UI在结构组合、能力组合之上,新增状态分层组合思想,根治传统 View 状态混乱问题。
核心准则:状态上提、单向数据流、无状态组件优先。
- 无状态组件:纯UI渲染单元,无内部状态、无业务逻辑,可复用、可测试、极致稳定;
- 状态容器:集中托管数据与状态,向下分发、向上监听,职责完全分离。
状态分层后的单向数据流如下:
#mermaid-svg-cFk9zSEbns7ihX2o{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-cFk9zSEbns7ihX2o .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-cFk9zSEbns7ihX2o .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-cFk9zSEbns7ihX2o .error-icon{fill:#552222;}#mermaid-svg-cFk9zSEbns7ihX2o .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-cFk9zSEbns7ihX2o .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-cFk9zSEbns7ihX2o .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-cFk9zSEbns7ihX2o .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-cFk9zSEbns7ihX2o .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-cFk9zSEbns7ihX2o .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-cFk9zSEbns7ihX2o .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-cFk9zSEbns7ihX2o .marker{fill:#333333;stroke:#333333;}#mermaid-svg-cFk9zSEbns7ihX2o .marker.cross{stroke:#333333;}#mermaid-svg-cFk9zSEbns7ihX2o svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-cFk9zSEbns7ihX2o p{margin:0;}#mermaid-svg-cFk9zSEbns7ihX2o .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-cFk9zSEbns7ihX2o .cluster-label text{fill:#333;}#mermaid-svg-cFk9zSEbns7ihX2o .cluster-label span{color:#333;}#mermaid-svg-cFk9zSEbns7ihX2o .cluster-label span p{background-color:transparent;}#mermaid-svg-cFk9zSEbns7ihX2o .label text,#mermaid-svg-cFk9zSEbns7ihX2o span{fill:#333;color:#333;}#mermaid-svg-cFk9zSEbns7ihX2o .node rect,#mermaid-svg-cFk9zSEbns7ihX2o .node circle,#mermaid-svg-cFk9zSEbns7ihX2o .node ellipse,#mermaid-svg-cFk9zSEbns7ihX2o .node polygon,#mermaid-svg-cFk9zSEbns7ihX2o .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-cFk9zSEbns7ihX2o .rough-node .label text,#mermaid-svg-cFk9zSEbns7ihX2o .node .label text,#mermaid-svg-cFk9zSEbns7ihX2o .image-shape .label,#mermaid-svg-cFk9zSEbns7ihX2o .icon-shape .label{text-anchor:middle;}#mermaid-svg-cFk9zSEbns7ihX2o .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-cFk9zSEbns7ihX2o .rough-node .label,#mermaid-svg-cFk9zSEbns7ihX2o .node .label,#mermaid-svg-cFk9zSEbns7ihX2o .image-shape .label,#mermaid-svg-cFk9zSEbns7ihX2o .icon-shape .label{text-align:center;}#mermaid-svg-cFk9zSEbns7ihX2o .node.clickable{cursor:pointer;}#mermaid-svg-cFk9zSEbns7ihX2o .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-cFk9zSEbns7ihX2o .arrowheadPath{fill:#333333;}#mermaid-svg-cFk9zSEbns7ihX2o .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-cFk9zSEbns7ihX2o .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-cFk9zSEbns7ihX2o .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-cFk9zSEbns7ihX2o .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-cFk9zSEbns7ihX2o .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-cFk9zSEbns7ihX2o .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-cFk9zSEbns7ihX2o .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-cFk9zSEbns7ihX2o .cluster text{fill:#333;}#mermaid-svg-cFk9zSEbns7ihX2o .cluster span{color:#333;}#mermaid-svg-cFk9zSEbns7ihX2o div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-cFk9zSEbns7ihX2o .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-cFk9zSEbns7ihX2o rect.text{fill:none;stroke-width:0;}#mermaid-svg-cFk9zSEbns7ihX2o .icon-shape,#mermaid-svg-cFk9zSEbns7ihX2o .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-cFk9zSEbns7ihX2o .icon-shape p,#mermaid-svg-cFk9zSEbns7ihX2o .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-cFk9zSEbns7ihX2o .icon-shape .label rect,#mermaid-svg-cFk9zSEbns7ihX2o .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-cFk9zSEbns7ihX2o .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-cFk9zSEbns7ihX2o .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-cFk9zSEbns7ihX2o :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 向下分发 count
向上回调 onAddClick
状态变更触发重组
状态容器 StatefulCounterWrapper
无状态组件 StatelessCounter
状态分层完整示例
kotlin
// 纯无状态UI:可全局复用
@Composable
fun StatelessCounter(count: Int, onAddClick: () -> Unit) {
Row(horizontalArrangement = Arrangement.spacedBy(16.dp)) {
Text("$count", style = MaterialTheme.typography.headlineMedium)
Button(onClick = onAddClick) { Text("+1") }
}
}
// 状态托管层:只管理状态,不渲染UI
@Composable
fun StatefulCounterWrapper() {
var count by remember { mutableStateOf(0) }
StatelessCounter(
count = count,
onAddClick = { count++ }
)
}
UI与状态彻底解耦,组合结构清晰、数据流可控、项目可维护性大幅提升。
八、跨框架横向辨析:Flutter / Compose / SwiftUI 统一设计准则
三大声明式框架均保留基类或协议契约,但定位完全不同:继承/协议仅用于适配框架契约,绝不用于业务拓展。
- Flutter 保留
StatelessWidget/StatefulWidget基类; - SwiftUI 保留
View协议; - Compose 以
@Composable函数契约替代继承。
以 Flutter 为例:
dart
class IconTextButton extends StatelessWidget {
final String text;
final Widget icon;
final VoidCallback onTap;
const IconTextButton({
super.key,
required this.text,
required this.icon,
required this.onTap,
});
@override
Widget build(BuildContext context) {
return ElevatedButton(
onPressed: onTap,
child: Row(
mainAxisSize: MainAxisSize.min,
children: [icon, const SizedBox(width: 6), Text(text)],
),
);
}
}
SwiftUI 同样以协议契约承载组合:
swift
struct IconTextButton: View {
let text: String
let icon: Image
let onTap: () -> Void
var body: some View {
Button(action: onTap) {
HStack(spacing: 6) {
icon
Text(text)
}
}
}
}
三大主流框架统一共识:
- Flutter:底层基类继承,业务100%组合;
- Jetpack Compose:纯函数范式,消除业务继承;
- SwiftUI:协议驱动,视图拓展完全依赖组合。
继承保底,组合为王。
九、组合优先范式的七大核心工程收益
-
系统可持续生长,无臃肿腐化
底层原子永久稳定,业务迭代仅调整组合结构,系统持续健康拓展。
-
单一职责解耦,降低团队认知成本
少量基础原子即可拼装全量界面,无需阅读巨型源码。
-
缺陷局部收敛,稳定性更高
无状态组件输入输出固定,问题仅局限于单组件,不会链式崩盘。
-
能力正交独立,消灭子类爆炸
样式、布局、交互自由组合,无需重复新建拓展类。
-
跨平台复用性极强
原子组件纯粹通用,支撑 Flutter、Compose Multiplatform 等跨平台架构复用。
-
迭代成本极低,试错灵活
仅调整组合参数与结构,不触碰底层,改动低风险、可回滚。
-
响应式精准刷新,性能极致优化
状态驱动最小刷新,避免全局重绘冗余。
核心内核总结:以稳定细粒度原子承载无穷业务变化,将复杂度收敛于组合关系,而非单体内部。
组合优先范式的整体收益可以归纳为下图:
#mermaid-svg-sTUuOU6BEQYAHOne{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-sTUuOU6BEQYAHOne .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-sTUuOU6BEQYAHOne .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-sTUuOU6BEQYAHOne .error-icon{fill:#552222;}#mermaid-svg-sTUuOU6BEQYAHOne .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-sTUuOU6BEQYAHOne .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-sTUuOU6BEQYAHOne .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-sTUuOU6BEQYAHOne .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-sTUuOU6BEQYAHOne .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-sTUuOU6BEQYAHOne .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-sTUuOU6BEQYAHOne .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-sTUuOU6BEQYAHOne .marker{fill:#333333;stroke:#333333;}#mermaid-svg-sTUuOU6BEQYAHOne .marker.cross{stroke:#333333;}#mermaid-svg-sTUuOU6BEQYAHOne svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-sTUuOU6BEQYAHOne p{margin:0;}#mermaid-svg-sTUuOU6BEQYAHOne .edge{stroke-width:3;}#mermaid-svg-sTUuOU6BEQYAHOne .section--1 rect,#mermaid-svg-sTUuOU6BEQYAHOne .section--1 path,#mermaid-svg-sTUuOU6BEQYAHOne .section--1 circle,#mermaid-svg-sTUuOU6BEQYAHOne .section--1 polygon,#mermaid-svg-sTUuOU6BEQYAHOne .section--1 path{fill:hsl(240, 100%, 76.2745098039%);}#mermaid-svg-sTUuOU6BEQYAHOne .section--1 text{fill:#ffffff;}#mermaid-svg-sTUuOU6BEQYAHOne .node-icon--1{font-size:40px;color:#ffffff;}#mermaid-svg-sTUuOU6BEQYAHOne .section-edge--1{stroke:hsl(240, 100%, 76.2745098039%);}#mermaid-svg-sTUuOU6BEQYAHOne .edge-depth--1{stroke-width:17;}#mermaid-svg-sTUuOU6BEQYAHOne .section--1 line{stroke:hsl(60, 100%, 86.2745098039%);stroke-width:3;}#mermaid-svg-sTUuOU6BEQYAHOne .disabled,#mermaid-svg-sTUuOU6BEQYAHOne .disabled circle,#mermaid-svg-sTUuOU6BEQYAHOne .disabled text{fill:lightgray;}#mermaid-svg-sTUuOU6BEQYAHOne .disabled text{fill:#efefef;}#mermaid-svg-sTUuOU6BEQYAHOne .section-0 rect,#mermaid-svg-sTUuOU6BEQYAHOne .section-0 path,#mermaid-svg-sTUuOU6BEQYAHOne .section-0 circle,#mermaid-svg-sTUuOU6BEQYAHOne .section-0 polygon,#mermaid-svg-sTUuOU6BEQYAHOne .section-0 path{fill:hsl(60, 100%, 73.5294117647%);}#mermaid-svg-sTUuOU6BEQYAHOne .section-0 text{fill:black;}#mermaid-svg-sTUuOU6BEQYAHOne .node-icon-0{font-size:40px;color:black;}#mermaid-svg-sTUuOU6BEQYAHOne .section-edge-0{stroke:hsl(60, 100%, 73.5294117647%);}#mermaid-svg-sTUuOU6BEQYAHOne .edge-depth-0{stroke-width:14;}#mermaid-svg-sTUuOU6BEQYAHOne .section-0 line{stroke:hsl(240, 100%, 83.5294117647%);stroke-width:3;}#mermaid-svg-sTUuOU6BEQYAHOne .disabled,#mermaid-svg-sTUuOU6BEQYAHOne .disabled circle,#mermaid-svg-sTUuOU6BEQYAHOne .disabled text{fill:lightgray;}#mermaid-svg-sTUuOU6BEQYAHOne .disabled text{fill:#efefef;}#mermaid-svg-sTUuOU6BEQYAHOne .section-1 rect,#mermaid-svg-sTUuOU6BEQYAHOne .section-1 path,#mermaid-svg-sTUuOU6BEQYAHOne .section-1 circle,#mermaid-svg-sTUuOU6BEQYAHOne .section-1 polygon,#mermaid-svg-sTUuOU6BEQYAHOne .section-1 path{fill:hsl(80, 100%, 76.2745098039%);}#mermaid-svg-sTUuOU6BEQYAHOne .section-1 text{fill:black;}#mermaid-svg-sTUuOU6BEQYAHOne .node-icon-1{font-size:40px;color:black;}#mermaid-svg-sTUuOU6BEQYAHOne .section-edge-1{stroke:hsl(80, 100%, 76.2745098039%);}#mermaid-svg-sTUuOU6BEQYAHOne .edge-depth-1{stroke-width:11;}#mermaid-svg-sTUuOU6BEQYAHOne .section-1 line{stroke:hsl(260, 100%, 86.2745098039%);stroke-width:3;}#mermaid-svg-sTUuOU6BEQYAHOne .disabled,#mermaid-svg-sTUuOU6BEQYAHOne .disabled circle,#mermaid-svg-sTUuOU6BEQYAHOne .disabled text{fill:lightgray;}#mermaid-svg-sTUuOU6BEQYAHOne .disabled text{fill:#efefef;}#mermaid-svg-sTUuOU6BEQYAHOne .section-2 rect,#mermaid-svg-sTUuOU6BEQYAHOne .section-2 path,#mermaid-svg-sTUuOU6BEQYAHOne .section-2 circle,#mermaid-svg-sTUuOU6BEQYAHOne .section-2 polygon,#mermaid-svg-sTUuOU6BEQYAHOne .section-2 path{fill:hsl(270, 100%, 76.2745098039%);}#mermaid-svg-sTUuOU6BEQYAHOne .section-2 text{fill:#ffffff;}#mermaid-svg-sTUuOU6BEQYAHOne .node-icon-2{font-size:40px;color:#ffffff;}#mermaid-svg-sTUuOU6BEQYAHOne .section-edge-2{stroke:hsl(270, 100%, 76.2745098039%);}#mermaid-svg-sTUuOU6BEQYAHOne .edge-depth-2{stroke-width:8;}#mermaid-svg-sTUuOU6BEQYAHOne .section-2 line{stroke:hsl(90, 100%, 86.2745098039%);stroke-width:3;}#mermaid-svg-sTUuOU6BEQYAHOne .disabled,#mermaid-svg-sTUuOU6BEQYAHOne .disabled circle,#mermaid-svg-sTUuOU6BEQYAHOne .disabled text{fill:lightgray;}#mermaid-svg-sTUuOU6BEQYAHOne .disabled text{fill:#efefef;}#mermaid-svg-sTUuOU6BEQYAHOne .section-3 rect,#mermaid-svg-sTUuOU6BEQYAHOne .section-3 path,#mermaid-svg-sTUuOU6BEQYAHOne .section-3 circle,#mermaid-svg-sTUuOU6BEQYAHOne .section-3 polygon,#mermaid-svg-sTUuOU6BEQYAHOne .section-3 path{fill:hsl(300, 100%, 76.2745098039%);}#mermaid-svg-sTUuOU6BEQYAHOne .section-3 text{fill:black;}#mermaid-svg-sTUuOU6BEQYAHOne .node-icon-3{font-size:40px;color:black;}#mermaid-svg-sTUuOU6BEQYAHOne .section-edge-3{stroke:hsl(300, 100%, 76.2745098039%);}#mermaid-svg-sTUuOU6BEQYAHOne .edge-depth-3{stroke-width:5;}#mermaid-svg-sTUuOU6BEQYAHOne .section-3 line{stroke:hsl(120, 100%, 86.2745098039%);stroke-width:3;}#mermaid-svg-sTUuOU6BEQYAHOne .disabled,#mermaid-svg-sTUuOU6BEQYAHOne .disabled circle,#mermaid-svg-sTUuOU6BEQYAHOne .disabled text{fill:lightgray;}#mermaid-svg-sTUuOU6BEQYAHOne .disabled text{fill:#efefef;}#mermaid-svg-sTUuOU6BEQYAHOne .section-4 rect,#mermaid-svg-sTUuOU6BEQYAHOne .section-4 path,#mermaid-svg-sTUuOU6BEQYAHOne .section-4 circle,#mermaid-svg-sTUuOU6BEQYAHOne .section-4 polygon,#mermaid-svg-sTUuOU6BEQYAHOne .section-4 path{fill:hsl(330, 100%, 76.2745098039%);}#mermaid-svg-sTUuOU6BEQYAHOne .section-4 text{fill:black;}#mermaid-svg-sTUuOU6BEQYAHOne .node-icon-4{font-size:40px;color:black;}#mermaid-svg-sTUuOU6BEQYAHOne .section-edge-4{stroke:hsl(330, 100%, 76.2745098039%);}#mermaid-svg-sTUuOU6BEQYAHOne .edge-depth-4{stroke-width:2;}#mermaid-svg-sTUuOU6BEQYAHOne .section-4 line{stroke:hsl(150, 100%, 86.2745098039%);stroke-width:3;}#mermaid-svg-sTUuOU6BEQYAHOne .disabled,#mermaid-svg-sTUuOU6BEQYAHOne .disabled circle,#mermaid-svg-sTUuOU6BEQYAHOne .disabled text{fill:lightgray;}#mermaid-svg-sTUuOU6BEQYAHOne .disabled text{fill:#efefef;}#mermaid-svg-sTUuOU6BEQYAHOne .section-5 rect,#mermaid-svg-sTUuOU6BEQYAHOne .section-5 path,#mermaid-svg-sTUuOU6BEQYAHOne .section-5 circle,#mermaid-svg-sTUuOU6BEQYAHOne .section-5 polygon,#mermaid-svg-sTUuOU6BEQYAHOne .section-5 path{fill:hsl(0, 100%, 76.2745098039%);}#mermaid-svg-sTUuOU6BEQYAHOne .section-5 text{fill:black;}#mermaid-svg-sTUuOU6BEQYAHOne .node-icon-5{font-size:40px;color:black;}#mermaid-svg-sTUuOU6BEQYAHOne .section-edge-5{stroke:hsl(0, 100%, 76.2745098039%);}#mermaid-svg-sTUuOU6BEQYAHOne .edge-depth-5{stroke-width:-1;}#mermaid-svg-sTUuOU6BEQYAHOne .section-5 line{stroke:hsl(180, 100%, 86.2745098039%);stroke-width:3;}#mermaid-svg-sTUuOU6BEQYAHOne .disabled,#mermaid-svg-sTUuOU6BEQYAHOne .disabled circle,#mermaid-svg-sTUuOU6BEQYAHOne .disabled text{fill:lightgray;}#mermaid-svg-sTUuOU6BEQYAHOne .disabled text{fill:#efefef;}#mermaid-svg-sTUuOU6BEQYAHOne .section-6 rect,#mermaid-svg-sTUuOU6BEQYAHOne .section-6 path,#mermaid-svg-sTUuOU6BEQYAHOne .section-6 circle,#mermaid-svg-sTUuOU6BEQYAHOne .section-6 polygon,#mermaid-svg-sTUuOU6BEQYAHOne .section-6 path{fill:hsl(30, 100%, 76.2745098039%);}#mermaid-svg-sTUuOU6BEQYAHOne .section-6 text{fill:black;}#mermaid-svg-sTUuOU6BEQYAHOne .node-icon-6{font-size:40px;color:black;}#mermaid-svg-sTUuOU6BEQYAHOne .section-edge-6{stroke:hsl(30, 100%, 76.2745098039%);}#mermaid-svg-sTUuOU6BEQYAHOne .edge-depth-6{stroke-width:-4;}#mermaid-svg-sTUuOU6BEQYAHOne .section-6 line{stroke:hsl(210, 100%, 86.2745098039%);stroke-width:3;}#mermaid-svg-sTUuOU6BEQYAHOne .disabled,#mermaid-svg-sTUuOU6BEQYAHOne .disabled circle,#mermaid-svg-sTUuOU6BEQYAHOne .disabled text{fill:lightgray;}#mermaid-svg-sTUuOU6BEQYAHOne .disabled text{fill:#efefef;}#mermaid-svg-sTUuOU6BEQYAHOne .section-7 rect,#mermaid-svg-sTUuOU6BEQYAHOne .section-7 path,#mermaid-svg-sTUuOU6BEQYAHOne .section-7 circle,#mermaid-svg-sTUuOU6BEQYAHOne .section-7 polygon,#mermaid-svg-sTUuOU6BEQYAHOne .section-7 path{fill:hsl(90, 100%, 76.2745098039%);}#mermaid-svg-sTUuOU6BEQYAHOne .section-7 text{fill:black;}#mermaid-svg-sTUuOU6BEQYAHOne .node-icon-7{font-size:40px;color:black;}#mermaid-svg-sTUuOU6BEQYAHOne .section-edge-7{stroke:hsl(90, 100%, 76.2745098039%);}#mermaid-svg-sTUuOU6BEQYAHOne .edge-depth-7{stroke-width:-7;}#mermaid-svg-sTUuOU6BEQYAHOne .section-7 line{stroke:hsl(270, 100%, 86.2745098039%);stroke-width:3;}#mermaid-svg-sTUuOU6BEQYAHOne .disabled,#mermaid-svg-sTUuOU6BEQYAHOne .disabled circle,#mermaid-svg-sTUuOU6BEQYAHOne .disabled text{fill:lightgray;}#mermaid-svg-sTUuOU6BEQYAHOne .disabled text{fill:#efefef;}#mermaid-svg-sTUuOU6BEQYAHOne .section-8 rect,#mermaid-svg-sTUuOU6BEQYAHOne .section-8 path,#mermaid-svg-sTUuOU6BEQYAHOne .section-8 circle,#mermaid-svg-sTUuOU6BEQYAHOne .section-8 polygon,#mermaid-svg-sTUuOU6BEQYAHOne .section-8 path{fill:hsl(150, 100%, 76.2745098039%);}#mermaid-svg-sTUuOU6BEQYAHOne .section-8 text{fill:black;}#mermaid-svg-sTUuOU6BEQYAHOne .node-icon-8{font-size:40px;color:black;}#mermaid-svg-sTUuOU6BEQYAHOne .section-edge-8{stroke:hsl(150, 100%, 76.2745098039%);}#mermaid-svg-sTUuOU6BEQYAHOne .edge-depth-8{stroke-width:-10;}#mermaid-svg-sTUuOU6BEQYAHOne .section-8 line{stroke:hsl(330, 100%, 86.2745098039%);stroke-width:3;}#mermaid-svg-sTUuOU6BEQYAHOne .disabled,#mermaid-svg-sTUuOU6BEQYAHOne .disabled circle,#mermaid-svg-sTUuOU6BEQYAHOne .disabled text{fill:lightgray;}#mermaid-svg-sTUuOU6BEQYAHOne .disabled text{fill:#efefef;}#mermaid-svg-sTUuOU6BEQYAHOne .section-9 rect,#mermaid-svg-sTUuOU6BEQYAHOne .section-9 path,#mermaid-svg-sTUuOU6BEQYAHOne .section-9 circle,#mermaid-svg-sTUuOU6BEQYAHOne .section-9 polygon,#mermaid-svg-sTUuOU6BEQYAHOne .section-9 path{fill:hsl(180, 100%, 76.2745098039%);}#mermaid-svg-sTUuOU6BEQYAHOne .section-9 text{fill:black;}#mermaid-svg-sTUuOU6BEQYAHOne .node-icon-9{font-size:40px;color:black;}#mermaid-svg-sTUuOU6BEQYAHOne .section-edge-9{stroke:hsl(180, 100%, 76.2745098039%);}#mermaid-svg-sTUuOU6BEQYAHOne .edge-depth-9{stroke-width:-13;}#mermaid-svg-sTUuOU6BEQYAHOne .section-9 line{stroke:hsl(0, 100%, 86.2745098039%);stroke-width:3;}#mermaid-svg-sTUuOU6BEQYAHOne .disabled,#mermaid-svg-sTUuOU6BEQYAHOne .disabled circle,#mermaid-svg-sTUuOU6BEQYAHOne .disabled text{fill:lightgray;}#mermaid-svg-sTUuOU6BEQYAHOne .disabled text{fill:#efefef;}#mermaid-svg-sTUuOU6BEQYAHOne .section-10 rect,#mermaid-svg-sTUuOU6BEQYAHOne .section-10 path,#mermaid-svg-sTUuOU6BEQYAHOne .section-10 circle,#mermaid-svg-sTUuOU6BEQYAHOne .section-10 polygon,#mermaid-svg-sTUuOU6BEQYAHOne .section-10 path{fill:hsl(210, 100%, 76.2745098039%);}#mermaid-svg-sTUuOU6BEQYAHOne .section-10 text{fill:black;}#mermaid-svg-sTUuOU6BEQYAHOne .node-icon-10{font-size:40px;color:black;}#mermaid-svg-sTUuOU6BEQYAHOne .section-edge-10{stroke:hsl(210, 100%, 76.2745098039%);}#mermaid-svg-sTUuOU6BEQYAHOne .edge-depth-10{stroke-width:-16;}#mermaid-svg-sTUuOU6BEQYAHOne .section-10 line{stroke:hsl(30, 100%, 86.2745098039%);stroke-width:3;}#mermaid-svg-sTUuOU6BEQYAHOne .disabled,#mermaid-svg-sTUuOU6BEQYAHOne .disabled circle,#mermaid-svg-sTUuOU6BEQYAHOne .disabled text{fill:lightgray;}#mermaid-svg-sTUuOU6BEQYAHOne .disabled text{fill:#efefef;}#mermaid-svg-sTUuOU6BEQYAHOne .section-root rect,#mermaid-svg-sTUuOU6BEQYAHOne .section-root path,#mermaid-svg-sTUuOU6BEQYAHOne .section-root circle,#mermaid-svg-sTUuOU6BEQYAHOne .section-root polygon{fill:hsl(240, 100%, 46.2745098039%);}#mermaid-svg-sTUuOU6BEQYAHOne .section-root text{fill:#ffffff;}#mermaid-svg-sTUuOU6BEQYAHOne .section-root span{color:#ffffff;}#mermaid-svg-sTUuOU6BEQYAHOne .section-2 span{color:#ffffff;}#mermaid-svg-sTUuOU6BEQYAHOne .icon-container{height:100%;display:flex;justify-content:center;align-items:center;}#mermaid-svg-sTUuOU6BEQYAHOne .edge{fill:none;}#mermaid-svg-sTUuOU6BEQYAHOne .mindmap-node-label{dy:1em;alignment-baseline:middle;text-anchor:middle;dominant-baseline:middle;text-align:center;}#mermaid-svg-sTUuOU6BEQYAHOne :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 组合优先范式
稳定原子
底层封闭
职责单一
灵活组合
结构嵌套
能力链式叠加
状态分层
工程收益
无臃肿腐化
缺陷局部收敛
跨平台复用
精准局部刷新
十、思维异同梳理:汉字造字与UI组件组合
相通核心(思维迁移依据)
- 原子固化、不新增底层单元;
- 简单单元组合生成复杂能力;
- 底层封闭、拓展依赖组合,符合开闭原则;
- 排列次序决定最终形态。
场景差异(精准区分认知边界)
- 动静差异:汉字静态、UI动态响应;
- 领域差异:汉字服务语义、UI服务交互渲染;
- 规则差异:汉字遵循字形语义、UI遵循渲染管线与状态机制。
二者思维模型同源、业务场景不同,完全适合用于类比学习,但不可混淆领域规则。
十一、结语
组合优先范式并非西式晦涩的架构玄学,而是人类构建复杂系统的通用真理。
东方汉字造字,以千年实践验证:有限原子,可组合万物;
西方软件工程,以现代框架验证:抛弃继承堆积,拥抱组合拓展是工程最优解。
借助国人熟悉的底层逻辑,我们终于穿透语法表层,看懂 Compose、Flutter、SwiftUI 的统一内核:
原子恒常,变化生于组合之间;少即是多,组合生无穷。