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

发布时间:2026/7/16 3:29:39

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/7/16 3:29:39

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

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

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

2026/7/16 3:29:39

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

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

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

2026/7/16 3:19:38

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

C++实现HDLC协议栈:从原理到嵌入式工业通信实战

C++实现HDLC协议栈:从原理到嵌入式工业通信实战

2026/7/16 5:49:45

1. 项目概述:为什么要在C里折腾HDLC?如果你在嵌入式、工业通信或者一些老牌通信设备公司的代码里翻过,大概率会碰到HDLC(高级数据链路控制)协议。乍一看,这协议名字里带个“高级”,但其实是上个…

PCB设计工程师核心技能与学习路径:从入门到进阶

PCB设计工程师核心技能与学习路径:从入门到进阶

2026/7/16 5:49:45

这次我们来聊聊PCB设计工程师这个岗位到底需要掌握哪些技能,哪些内容可以暂时放一放。对于刚入行的工程师来说,最头疼的就是不知道学习重点在哪里,担心学了一堆用不上的东西,反而错过了核心技能。PCB设计工程师主要负责电路板的设…

【AI总结】2026年6月 主流国内外大模型总结

【AI总结】2026年6月 主流国内外大模型总结

2026/7/16 5:49:45

目录 引言一、 国际主流模型 1. OpenAI GPT 系列2. Anthropic Claude 系列3. Google Gemini 系列4. Meta Llama 系列5. xAI Grok 系列6. 其他值得关注的国际模型 二、 国内主流模型 1. 百度 文心大模型2. 阿里 通义千问3. 腾讯 混元大模型4. 字节跳动 豆包大模型 / 扣子5. 智谱…

Java循环控制进阶:while与do..while的实战抉择与break/continue的精准调控

Java循环控制进阶:while与do..while的实战抉择与break/continue的精准调控

2026/7/16 5:49:45

1. 为什么需要while和do..while循环?在日常编程中,我们经常遇到需要重复执行某段代码的场景。比如读取用户输入直到输入合法、处理文件中的每一行数据、或者游戏中的主循环。这时候,循环结构就派上用场了。Java提供了三种主要的循环结构&…

【2014-01-27】cocos2dx学习笔记:CCNode回调流程

【2014-01-27】cocos2dx学习笔记:CCNode回调流程

2026/7/16 5:49:45

[历史归档] 本文原发布于 cstriker1407.info 个人博客,内容为历史存档,仅供参考。 发布时间: 2014-01-27 | 标题:cocos2dx学习笔记:CCNode回调流程 | 分类: 编程 / C &&…

OpenAI技术面试全攻略:算法、系统设计与项目经验解析

OpenAI技术面试全攻略:算法、系统设计与项目经验解析

2026/7/16 5:39:44

最近在技术圈里,OpenAI 的面试体验又成了热门话题。不少开发者分享了自己参与面试的经历,普遍反馈流程专业、题目有深度,特别是对算法基础和系统设计能力的考察很到位。这让很多正在准备面试或对 AI 领域感兴趣的同学跃跃欲试。不过也有网友调…

Unity游戏文本翻译架构深度解析:XUnity.AutoTranslator的技术实现与工程实践

Unity游戏文本翻译架构深度解析:XUnity.AutoTranslator的技术实现与工程实践

2026/7/16 0:35:09

Unity游戏文本翻译架构深度解析:XUnity.AutoTranslator的技术实现与工程实践 【免费下载链接】XUnity.AutoTranslator 项目地址: https://gitcode.com/gh_mirrors/xu/XUnity.AutoTranslator XUnity.AutoTranslator作为Unity游戏社区中最成熟的文本翻译解决方…

openEuler Raspberry Pi Kernel设备驱动开发指南:为树莓派硬件添加支持

openEuler Raspberry Pi Kernel设备驱动开发指南:为树莓派硬件添加支持

2026/7/13 20:43:19

openEuler Raspberry Pi Kernel设备驱动开发指南:为树莓派硬件添加支持 【免费下载链接】raspberrypi-kernel It provides openEuler kernel source for Raspberry Pi 项目地址: https://gitcode.com/openeuler/raspberrypi-kernel 前往项目官网免费下载&…

openEuler系统集成测试实战:基于smoke-test套件的环境验证技巧

openEuler系统集成测试实战:基于smoke-test套件的环境验证技巧

2026/7/15 0:26:43

openEuler系统集成测试实战:基于smoke-test套件的环境验证技巧 【免费下载链接】integration-test The repo contains test suits for system integration test 项目地址: https://gitcode.com/openeuler/integration-test 前往项目官网免费下载:…

Python实现跨境电商商品图批量翻译教程

Python实现跨境电商商品图批量翻译教程

2026/7/16 0:09:31

一、问题引入做跨境电商的卖家朋友,你是否遇到过这样的困扰?每次上架新品到亚马逊、Shopee或Lazada等平台,都需要处理大量商品图片的多语言版本。比如上架200款衣服,每款需要翻译成英语、日语、韩语等5种语言,这意味着…

跨境电商多语言商品图翻译方案实现

跨境电商多语言商品图翻译方案实现

2026/7/16 0:09:31

一、问题引入对于做跨境电商的卖家来说,多语言商品图的制作一直是令人头疼的环节。当你准备在亚马逊、Shopee、Lazada等多个平台同步上架新品时,首先遇到的就是图片翻译问题。以一位做家居用品的卖家为例,他需要将200张商品图片中的英文文案全…

Windows系统文件d3dx9_36.dll丢失找不到问题解决

Windows系统文件d3dx9_36.dll丢失找不到问题解决

2026/7/16 0:09:31

在使用电脑系统时经常会出现丢失找不到某些文件的情况,由于很多常用软件都是采用 Microsoft Visual Studio 编写的,所以这类软件的运行需要依赖微软Visual C运行库,比如像 QQ、迅雷、Adobe 软件等等,如果没有安装VC运行库或者安装…