当前位置: 首页 > news >正文

【Typescript】11-类抽象类与面向对象建模

类、抽象类与面向对象建模

TypeScript 不是一门纯粹的面向对象语言,但它对类系统的支持足够完整,足以覆盖很多工程场景。问题在于,很多人学到class之后,会误以为这就是组织 TypeScript 代码的默认方式。现实恰恰相反:类是重要工具,但不是默认答案。

这一篇的重点,不是带你机械复习“什么是封装、继承、多态”,而是更现实地回答三个问题:

  • TypeScript 里的类到底能做什么
  • 抽象类和接口分别适合什么位置
  • 在现代 JavaScript/TypeScript 工程里,什么时候该用类,什么时候不该用

类首先是一种“带状态和行为的实例模型”

最基本的类写法如下:

classUser{constructor(publicid:number,publicname:string){}greet(){return`Hello,${this.name}`;}}

这里的public id: numberpublic name: string是一种语法简写,表示:

  • 在构造函数接收参数
  • 同时把它们声明成实例属性

这使得类特别适合表达“一个对象既有数据,又有围绕这些数据运作的方法”的场景。

类和普通对象最大的区别,不在语法,而在实例语义

普通对象很适合表示数据:

constuser={id:1,name:"Alice"};

而类更适合表示“可被实例化、可带行为、可能有生命周期”的实体:

classTimer{privatestartTime=Date.now();getElapsedTime(){returnDate.now()-this.startTime;}}

所以你可以把类理解成一种更强的组织方式,但前提是你真的需要这种“实例化对象 + 行为封装”的模型。

访问修饰符让类更适合做封装

TypeScript 支持这些访问修饰符:

  • public
  • private
  • protected
  • readonly

看一个例子:

classAccount{publicowner:string;privatebalance:number;constructor(owner:string,balance:number){this.owner=owner;this.balance=balance;}deposit(amount:number){this.balance+=amount;}getBalance(){returnthis.balance;}}

这里:

  • owner可以在外部访问
  • balance只能在类内部访问

private的价值不只是“防止乱改”,更是让你能够清晰地区分:

  • 哪些是对外暴露的稳定接口
  • 哪些是内部实现细节

这对于 SDK、服务对象、领域模型非常重要。

protected适合“对子类开放、对外部隐藏”

classBaseService{protectedlog(message:string){console.log("[service]",message);}}classUserServiceextendsBaseService{createUser(){this.log("create user");}}

protected允许子类使用,但外部实例不能直接访问。这类能力在可继承的基类设计里很常见。

readonly能表达对象生命周期中的不变部分

classOrder{constructor(publicreadonlyid:string,publicstatus:"pending"|"paid"){}}

这里的id一旦构造完成就不允许再变。这个约束非常贴近业务语义,也比靠注释说“不要改它”更可靠。

实现接口:把能力边界和实现细节分开

interfaceLogger{log(message:string):void;}classConsoleLoggerimplementsLogger{log(message:string){console.log(message);}}

这里接口和类的分工非常清楚:

  • 接口定义“应该具备什么能力”
  • 类负责“具体怎么实现”

这种模式在这些场景中非常常见:

  • 依赖注入
  • 策略模式
  • 适配器模式
  • 可替换服务实现

如果你希望系统依赖的是能力,而不是某个具体类,接口就很重要。

抽象类:适合“部分规则固定,部分细节留给子类”

抽象类和接口容易被混淆,但它们解决的问题不完全一样。看一个例子:

abstractclassAnimal{abstractspeak():void;move(){console.log("moving");}}classDogextendsAnimal{speak(){console.log("wang");}}

这里:

  • Animal不能直接被实例化
  • 它提供了通用实现move()
  • 同时强制子类实现speak()

你可以把抽象类理解成“半成品基类”。它适合那些:

  • 某些流程是固定的
  • 但某些具体步骤必须交给不同子类补齐

接口和抽象类怎么选

一个简单的判断标准:

  • 如果你只想描述能力契约,用接口
  • 如果你还想提供一部分共享实现,用抽象类

接口更轻,耦合更低;抽象类更强,但也更容易把继承树绑得太紧。工程上通常是优先接口,只有当共享实现真的有价值时,再考虑抽象类。

继承不是错,但通常不是第一选择

现代 JavaScript/TypeScript 社区对继承更谨慎,不是因为继承不能用,而是因为很多系统最后都会被深层继承链搞得越来越难维护。

例如:

  • 父类改一点,多个子类都受影响
  • 子类不小心依赖了父类内部实现细节
  • 行为分发越来越难追踪

所以比起“默认继承”,很多项目更倾向于:

  • 对象组合
  • 函数式封装
  • 接口 + 多实现

这类方式通常更灵活,也更适合现代前端和 Node.js 工程。

类什么时候真的有优势

类最适合这些场景:

  • SDK 封装
  • 带内部状态的服务对象
  • 插件系统
  • 有生命周期管理的对象
  • 明确存在多种实现并共享部分基础逻辑的体系

例如数据库客户端、消息队列客户端、缓存实例、编辑器插件体系,都很适合类。

类什么时候反而会让事情更糟

如果你只是想表达一份数据,或者封装一段纯函数逻辑,类很可能会引入额外复杂度。

例如:

  • 一个简单工具函数库
  • 一组纯数据转换逻辑
  • 一个没有实例状态的工具模块

这些场景里,普通函数和对象字面量往往更清晰。

一个更现实的 TypeScript 观点

学类系统当然重要,但更重要的是别被“类就是高级架构”的幻觉带偏。真正成熟的工程判断不是“我会不会写 class”,而是“这段问题到底需要实例、封装、继承、多态中的哪一种能力”。

如果答案都不需要,那就别强上类。

本文小结

TypeScript 的类系统足够强,抽象类、访问修饰符、接口实现都能支持你完成相当完整的面向对象建模。但类不是默认模板,而是一种在合适场景下非常有效的组织工具。真正好的设计,不是让代码更像教科书里的 OOP,而是让业务边界更清楚、职责更稳定、扩展更自然。

练习

  1. 写一个Shape抽象类,包含getArea()抽象方法和一个通用的printName()方法。
  2. 用接口定义Payment,然后实现WechatPaymentAlipayPayment两个类,并比较接口与抽象类在这个场景中的区别。
  3. 选择你项目里的一个工具模块,思考它究竟更适合普通函数还是类,说明理由。

后记

2026年5月22日于上海。

http://www.jsqmd.com/news/867528/

相关文章:

  • 西南文创礼品定制技术拆解:高端礼品定制/会议纪念礼品/各类礼品团购/商务礼品定制/成都礼品批量定制/成都礼品批量订制/选择指南 - 优质品牌商家
  • 庞加莱猜想:哲学 × 数学 思维范式全链条
  • Stargazer AI Copilot Desktop 使用说明
  • 0x.Tools快速入门:10分钟内掌握Linux系统性能分析
  • 3个步骤掌握Betaflight飞控固件:从零开始打造专业级无人机飞行体验
  • 咋选北京装修公司?2026年5月推荐TOP10对比旧房翻新防超支评测适用场景特点 - 品牌推荐
  • 【Typescript】12-模块声明文件与第三方库
  • PHP 文件:深入解析与最佳实践
  • 【Sora 2批量视频生成黄金工作流】:实测吞吐提升4.8倍的关键配置——NVIDIA A100集群下每小时稳定输出217段1080p视频
  • WireUI颜色选择器和日期选择器:提升用户体验的利器 [特殊字符][特殊字符]
  • 如何选择深度学习数据集?Awesome Deep Learning Resources 实用资源解析
  • 创业公司如何利用 Taotoken 统一管理多个 AI 模型服务
  • Solaar 4.0:解锁罗技设备的完整Linux管理体验
  • 【Typescript】13-tsconfig与工程化实践
  • Sora 2提示词失效真相大起底(92%用户踩中的3类语义断层陷阱)
  • 2026年5月北京老房改造装修公司推荐:TOP5排名专业评测防隐患价格 - 品牌推荐
  • Ruby XML, XSLT 和 XPath 教程
  • 如何用killport一键清理占用端口的进程和容器:终极端口管理指南
  • Structured3D完整指南:如何用3D结构化数据轻松构建智能室内场景
  • CreamInstaller终极指南:一键解锁Steam、Epic、Ubisoft游戏DLC的完整教程
  • AI生成镜头如何通过DIT审核?——Netflix《The Last Frame》技术白皮书首度公开(附VFX合规性检查清单PDF)
  • 纳维-斯托克斯方程:哲学 × 数学 思维范式全链条
  • 混合专家MoE拆解:GPT-4、千问、DeepSeek为什么都选这个架构
  • 【Typescript】14-高级实战-设计类型安全的-api
  • 终极Rufus教程:轻松制作Windows启动U盘的全方位指南
  • Perplexity反义词≠低困惑度?——斯坦福NLP实验室内部培训材料首次公开的4层认知陷阱
  • SSZipArchive:Apple全平台专业级ZIP文件处理解决方案
  • 10个sd-webui-regional-prompter实用技巧:从基础分割到高级2D区域配置
  • 2026粉末包装机十大品牌排名 广州恒尔凭借过硬实力跻身优质品牌行列 - 品牌速递
  • (总结)七大数学猜想:哲学 × 数学 思维范式全链条