HarmonyOS 应用开发《掌上英语》第13篇:面向对象 vs 函数式:ArkTS 中的编程范式选择

发布时间:2026/9/28 4:42:40

HarmonyOS 应用开发《掌上英语》第13篇:面向对象 vs 函数式:ArkTS 中的编程范式选择
面向对象 vs 函数式ArkTS 中的编程范式选择一、引言ArkTS 是 HarmonyOS 原生开发语言它在 TypeScript 基础上增强了静态类型检查和装饰器体系同时保留了多范式的表达能力。在实际项目开发中我们经常面临一个选择用面向对象OOP还是函数式FP这个问题没有绝对答案——每种范式都有其擅长的领域。本文将以我们英语学习 App 的实际代码为例分析 class ObservedV2的面向对象模型、Builder参数化 UI 片段、以及函数式单例工具类如AudioPlayer的设计思路帮你理清在 ArkTS 中如何做出合理的范式选择。二、面向对象范式class ObservedV2 响应式模型2.1 WordCard 数据模型在 ArkTS V2 装饰器体系中ObservedV2Trace是实现响应式数据模型的标准方式。它的本质是面向对象的——通过 class 封装数据用装饰器标记可观察属性// commonLib/models/WordCardModel.etsObservedV2exportclassWordCard{Traceid:number0;Traceword:string;Tracephonetic:string;TracepartOfSpeech:string;Tracetranslation:string;Traceexample:string;TraceexampleTranslation:string;TraceaudioUrl:string;Tracetags:string[][];Tracecategory:stringbasic;constructor(id:number,word:string,phonetic:string,partOfSpeech:string,translation:string,example:string,exampleTranslation:string,audioUrl:string,tags:string[][],category:stringbasic){this.idid;this.wordword;// ... 其余字段赋值}}为什么选 class 而非 plain object在 ArkTS 中普通的对象字面量{ word: apple, ... }无法被Trace追踪。只有通过ObservedV2装饰的 class 实例其Trace属性变化才能触发 UI 刷新。这是面向对象范式在 ArkTS 响应式体系中的核心优势——class 不是可选的而是响应式的基础。2.2 ObservedV2 的工作原理当你在ComponentV2装饰的组件中读取wordCard.word时ArkTS 框架会自动建立属性→组件的依赖关系。一旦wordCard.word被修改只有读取了这个特定字段的组件会重新渲染——其他未依赖的组件不受影响。ComponentV2struct WordDisplay{ParamwordCard:WordCardnewWordCard();build(){Text(this.wordCard.word)// 只依赖 word 字段.fontSize(34);Text(this.wordCard.phonetic)// 只依赖 phonetic 字段.fontSize(15);}}这种字段级粒度的响应式追踪是面向对象方案独有的能力。如果改用函数式不可变数据每次修改都需要创建新对象并整体重新赋值性能开销大且代码更繁琐。2.3 CourseCoreBar封装业务逻辑的类除了数据模型面向对象也适合封装带有行为的状态// MainPage.etsObservedV2exportclassCourseCoreBar{TraceshowIcon:ResourceStr;Tracedescription:string;constructor(showIcon:ResourceStr,description:string){this.showIconshowIcon;this.descriptiondescription;}}这类带状态的业务对象天然适合 class——它同时承载数据和 UI 依赖的响应式属性无需在组件内部维护额外的状态管理逻辑。三、函数式范式Builder 与工具类3.1 Builder参数化 UI 片段ArkTS 的Builder是一个纯粹的 UI 函数——它接收参数返回 UI 描述没有内部状态。这正是函数式编程中纯函数的体现// CourseHomePage.etsBuildertabBuilder(label:string,key:string){Text(label).fontSize(14).fontColor(this.currentCategorykey?#165DFF:$r(sys.color.font_secondary)).fontWeight(this.currentCategorykey?FontWeight.Bold:FontWeight.Normal).padding({left:12,right:12,top:6,bottom:6});}// 在 build() 中调用TabContent(){this.cardArea();}.tabBar(this.tabBuilder(全部,all));Builder的优势在于无副作用输入相同参数输出相同 UI可组合多个Builder可以嵌套组合按需复用同一段 UI 逻辑在不同位置调用只需传不同参数对于不需要内部状态的 UI 片段用Builder而非创建一个新组件可以减少组件树的层次提升渲染性能。3.2 Builder 导出模式项目采用统一的 Builder 导出模式将每个页面的构建函数暴露给路由系统// CourseHomePage.ets 末尾BuilderexportfunctionCourseHomePageBuilder(){CourseHomePage();}这是一种工厂函数风格——CourseHomePageBuilder是一个纯函数每次调用都创建新的组件实例。路由系统通过RouterTable统一管理这些 Builder// RouterTable.etsRouterTable.builderMap.set(RouterMap.WORD_CARD_PAGE,wrapBuilder(WordCardPageBuilder));这种模式将创建组件的职责从组件内部剥离出来实现了更干净的关注点分离。3.3 AudioPlayer单例模式中的函数式设计AudioPlayer虽然使用了 class 语法但它的设计理念更接近函数式——全局唯一实例无 UI 依赖// commonLib/utils/AudioPlayer.etsexportclassAudioPlayer{privatestaticinstance?:AudioPlayer;privateavPlayer:media.AVPlayer|nullnull;privatecurrentUrl:string;privateconstructor(){}publicstaticgetInstance():AudioPlayer{if(!AudioPlayer.instance){AudioPlayer.instancenewAudioPlayer();AudioPlayer.instance.initPlayer();}returnAudioPlayer.instance;}publicplay(url:string):void{if(!url||url)return;if(!this.avPlayer)return;// ... 播放逻辑}publicstop():void{/* ... */}publicrelease():void{/* ... */}}工具类使用单例 方法的模式有几个优点无状态副作用每次调用play()只依赖传入的 URL 参数全局复用任何一个页面都可以通过AudioPlayer.getInstance().play(url)播放音频无 UI 耦合可以在非 UI 线程中使用不受组件生命周期影响类似的还有NewWordManager、GlobalContextUtils等工具类都采用同样的单例 方法设计。四、范式对比何时用哪种维度面向对象 (class)函数式 (Builder / 单例)状态管理Trace字段级追踪适合 UI 数据无状态或全局单例适合工具能力复用方式继承、组合、依赖注入参数化、高阶函数响应式原生支持属性变化自动刷新 UI不涉及响应式适合非 UI 逻辑测试难度需要 mock 状态和装饰器环境纯函数测试简单典型场景数据模型、ViewModel、业务实体UI 片段复用、工具类、路由工厂选择指南数据模型→ 用 class ObservedV2。需要响应式追踪的属性加上Trace确保 UI 自动刷新。UI 复用片段→ 用Builder。当一段 UI 只是带参数的模板且不需要独立生命周期时Builder比抽取成独立组件更轻量。工具类/服务类→ 用单例 方法。如音频播放、网络请求、数据持久化这些不依赖 UI 状态的功能适合函数式风格。组件创建工厂→ 用导出函数Builder 模式。将组件的创建与路由解耦方便路由表统一管理。五、混合范式的最佳实践实际项目中两种范式不是互斥的而是互补的。以下是我们项目中的混合使用模式// 1. 面向对象ViewModel 管理状态ObservedV2classTopicVM{TracecurrentIndex:number0;// ... 响应式属性}// 2. 函数式Builder 创建组件BuilderexportfunctionTopicPageBuilder(){TopicPage();}// 3. 工具类单例全局服务constaudioPlayerAudioPlayer.getInstance();audioPlayer.play(hello.mp3);// 4. Builder 复用 UI 片段在组件内部BuildercommonHeader(title:string){Text(title).fontSize(18).fontWeight(FontWeight.Bold);}核心原则有状态的用 class无状态的用函数。ArkTS V2 的装饰器体系让面向对象在 UI 层如鱼得水而函数式风格在工具层保持简洁和可测试性。理解两种范式的优劣在合适的场景选择合适的方式比固执于一种纯范式要实用得多。六、总结在 ArkTS 中面向对象和函数式编程并非二选一的对立关系而是一枚硬币的两面面向对象class ObservedV2/Trace是 ArkTS 响应式 UI 的基础适合数据模型、ViewModel 和业务实体函数式Builder、单例工具类在 UI 片段复用、工具服务和无状态逻辑中更简洁混合使用是最佳实践数据层用 OOP 保证响应式工具层用 FP 保证可测试性理解每种范式的设计意图和适用场景才能写出既符合 ArkTS 平台特性又易于维护的代码。

相关新闻

数字信号处理实战----FPGA中的多速率滤波与采样率转换

数字信号处理实战----FPGA中的多速率滤波与采样率转换

2026/8/22 17:38:59

1. 多速率信号处理的核心概念我第一次在FPGA上实现采样率转换时,被频谱混叠问题折磨得够呛。当时用160MHz采样70MHz中频信号,结果因为没处理好抽取倍数,整个频谱乱成一锅粥。多速率信号处理本质上就是智能地操控采样率,就像给高速…

Copilot Token 计费真相:个人开发者必懂的成本精算与优化指南

Copilot Token 计费真相:个人开发者必懂的成本精算与优化指南

2026/8/25 22:50:45

1. 这不是“订阅费”,而是“按次精算的代码燃料费”——个人开发者必须看懂的 Copilot Token 计费真相你有没有在 VS Code 里敲下几行注释,Copilot 就弹出一个“正在思考…”的提示,然后光标停顿半秒、补全了一整段函数?那一刻你大…

C++编程入门指南:从基础语法到实战项目的完整学习路径

C++编程入门指南:从基础语法到实战项目的完整学习路径

2026/9/4 9:40:45

如果你正在考虑学习编程,或者已经接触过一些编程语言但想深入了解系统级开发,那么C绝对是一个绕不开的话题。但很多人对C的第一印象往往是"复杂"、"难学"、"指针容易出错"——这些标签让不少初学者望而却步。事实上&#…

CANN/GE ACL数据集缓冲区添加函数

CANN/GE ACL数据集缓冲区添加函数

2026/9/28 4:08:17

aclmdlAddDatasetBuffer 【免费下载链接】ge GE(Graph Engine)是面向昇腾的图编译器和执行器,提供了计算图优化、多流并行、内存复用和模型下沉等技术手段,加速模型执行效率,减少模型内存占用。 GE 提供对 PyTorch、Te…

用ffmpeg高效批量调整图片尺寸的实战指南

用ffmpeg高效批量调整图片尺寸的实战指南

2026/9/27 1:30:29

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

Transformers 音频特征提取工具库 audio_utils 全解析:从 Mel 刻度换算到对数 Mel 频谱

Transformers 音频特征提取工具库 audio_utils 全解析:从 Mel 刻度换算到对数 Mel 频谱

2026/9/28 2:15:29

Transformers 音频特征提取工具库 audio_utils 全解析:从 Mel 刻度换算到对数 Mel 频谱 【免费下载链接】transformers 🤗 Transformers: the model-definition framework for state-of-the-art machine learning models in text, vision, audio, and mu…

RustFS 多节点集群重启与滚动升级实战:Readiness、Quorum 与 Degraded 模式完全指南

RustFS 多节点集群重启与滚动升级实战:Readiness、Quorum 与 Degraded 模式完全指南

2026/9/28 3:14:54

RustFS 多节点集群重启与滚动升级实战:Readiness、Quorum 与 Degraded 模式完全指南 【免费下载链接】rustfs 🚀2.3x faster than MinIO for 4KB object payloads. RustFS is an open-source, S3-compatible high-performance object storage system sup…

Java Integer缓存揭秘:128陷阱原理、避坑与面试全解

Java Integer缓存揭秘:128陷阱原理、避坑与面试全解

2026/9/28 3:58:00

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

RustFS Scanner 数据用量发布权威性决策:配额准入如何获得可用的权威依据

RustFS Scanner 数据用量发布权威性决策:配额准入如何获得可用的权威依据

2026/9/28 3:47:14

RustFS Scanner 数据用量发布权威性决策:配额准入如何获得可用的权威依据 【免费下载链接】rustfs 🚀2.3x faster than MinIO for 4KB object payloads. RustFS is an open-source, S3-compatible high-performance object storage system supporting mi…

远程协作的工作台整理

远程协作的工作台整理

2026/9/26 14:29:04

远程协作的工作台整理远程协作的核心不是再加一个工具,而是让交接信息足够完整。异步任务要写明目标、输入位置、完成标准和需要决策的人。 工作台的最小配置 将日程、待办、代码和沟通入口收拢到少数固定位置;通知按紧急程度分层。工作台不需要模仿办公…

持续集成 流水线自动化与 声明式交付 实践:原型怎样变成可用功能

持续集成 流水线自动化与 声明式交付 实践:原型怎样变成可用功能

2026/9/26 13:57:22

持续集成 流水线自动化与 声明式交付 实践:原型怎样变成可用功能分类:[AI/大模型]细分主题:AI 增强型 CI/CD 流水线自动化与 GitOps 实践:Agent 工作流、工具调用与任务拆解:从原型到生产的验收清单很多团队在尝试用大…

容器编排 生产环境运维与排障实战:复盘记录怎样真正派上用场

容器编排 生产环境运维与排障实战:复盘记录怎样真正派上用场

2026/9/26 23:35:16

容器编排 生产环境运维与排障实战:复盘记录怎样真正派上用场分类:[工程技术]细分主题:Kubernetes 生产环境运维与排障实战:可复制的项目复盘模板与决策记录大部分团队的事故复盘报告,最后都变成了躺在 Confluence 或钉…