news 2026/4/23 3:46:57

软件工程就是一场“抽象”游戏:从 abstract 关键字到架构设计的认知跃迁

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
软件工程就是一场“抽象”游戏:从 abstract 关键字到架构设计的认知跃迁

写在前面

“我接触过的抽象,好像就是抽象类和抽象方法。抽象类里只能写抽象方法,子类必须重写。其他地方好像用到的不多……对了,有时候把数据展示给前端,好像也需要‘抽象’一层,返回给前端不同的对象。”

这是很多 Java 初学者的真实困惑。我们把“抽象”理解成了一个语法关键字,而不是一种设计思想。所以当听到“软件工程就是一个抽象的过程”这种话时,总觉得玄乎,和自己写的 CRUD 没什么关系。

但事实上,你每天都在不知不觉地使用抽象——只是你没有意识到。

  • 当你定义List接口而不是直接用ArrayList时,你在抽象

  • 当你把数据库的User实体转换成UserVO返回给前端时,你在抽象

  • 当你编写一个通用的RedisService封装了缓存逻辑时,你在抽象

  • 当你按照三层架构(Controller/Service/DAO)组织代码时,你更是在做宏观的抽象

今天,我们就从“abstract 关键字”出发,一路走到架构设计层面,彻底搞懂:抽象到底是什么?为什么说它是软件工程的核心?Java 开发者如何用好抽象这把利器?

一、什么是抽象?从地图说起

想象你要去一个陌生的城市。你会怎么做?

  • 你会拿到一张城市地图。地图上画了主要道路、地标建筑、公交线路。

  • 但地图上不会画出每一棵树、每一个井盖、每一户人家的窗户。

地图就是现实世界的“抽象”:它保留了关键信息(路怎么走、地标在哪),去掉了无关细节(树木、窗户)。这让你能快速理解城市结构,而不被海量细节淹没。

软件工程中的抽象,本质上和地图一样:忽略与当前目标无关的细节,聚焦于本质特征

  • 当你调用list.get(0)时,你不关心 ArrayList 内部是数组还是链表——List接口就是抽象

  • 当你发送 HTTP 请求时,你不关心底层 TCP 三次握手——HttpClient就是抽象

  • 当你使用@Transactional时,你不关心事务的开启、提交、回滚细节——Spring 帮你抽象了

抽象的目的不是让代码“变少”,而是让复杂度“可控”。通过分层抽象,我们才能在有限的大脑容量下构建出百万行级别的软件系统。

二、Java 中的抽象语法:abstract 关键字只是冰山一角

2.1 抽象类 vs 接口:纠正常见误区

很多初学者认为:“抽象类里只能有抽象方法,抽象方法必须重写。”

这是错误的。抽象类可以有:

  • 抽象方法(没有方法体,子类必须实现)

  • 具体方法(有方法体,子类可继承或重写)

  • 成员变量、构造器(虽然不能直接实例化,但可以被子类构造器调用)

public abstract class AbstractAnimal { private String name; // 可以有字段 public AbstractAnimal(String name) { // 可以有构造器 this.name = name; } public void eat() { // 具体方法,子类可直接使用 System.out.println(name + " is eating"); } public abstract void makeSound(); // 抽象方法,子类必须实现 }

抽象类和接口的选择原则

  • 抽象类:用于表示“is-a”关系(猫是一种动物),且需要共享状态或通用行为时

  • 接口:用于表示“can-do”关系(鸟会飞、车能跑),且需要多实现或完全解耦时

Java 8 之后接口可以有默认方法和静态方法,接口的能力大大增强。现代 Java 开发中,接口的使用频率远超抽象类。

2.2 抽象方法的重写:不是“被迫”,而是“填空”

抽象方法强制子类提供具体实现,这其实是模板方法模式的体现。父类定义“骨架”,子类填充“细节”。

public abstract class DataProcessor { // 模板方法:定义了处理流程的骨架 public final void process() { loadData(); processData(); saveResult(); } protected abstract void loadData(); // 子类实现 protected abstract void processData(); // 子类实现 protected abstract void saveResult(); // 子类实现 }

这种设计让核心流程不变,而具体步骤可以灵活替换。你在 Spring 中见过的JdbcTemplateRedisTemplate都大量使用了这种思想。

三、抽象在开发中的真实应用(你每天都在用)

3.1 面向接口编程:最经典的抽象实践

// 不抽象:直接依赖具体实现 private ArrayList<User> users = new ArrayList<>(); // 抽象:依赖接口 private List<User> users = new ArrayList<>();

为什么第二段更好?因为将来你可以把ArrayList换成LinkedListCopyOnWriteArrayList,而调用方代码(users.get(0)users.add(user))完全不用改。

依赖倒置原则:高层模块不应该依赖低层模块,二者都应该依赖抽象。你写的 Service 层应该依赖UserDao接口,而不是具体的UserDaoImpl

3.2 数据交互中的抽象:PO/DO/DTO/VO 的划分

你提到的“把数据展示给前端需要抽象一层”,这正是数据抽象最典型的例子。

  • PO(Persistent Object):数据库表结构的一对一映射,可能包含密码、创建时间等内部字段

  • VO(View Object):为前端定制的对象,只包含前端需要的字段,可能聚合多个 PO 的数据

如果直接把UserPO(包含passwordsalt)返回给前端,不仅泄露敏感信息,而且前端可能只需要nameavatar,传输了大量无用数据。

// 不好的抽象:直接暴露内部实体 @GetMapping("/user/{id}") public UserPO getUser(@PathVariable Long id) { ... } // 好的抽象:返回 VO @GetMapping("/user/{id}") public UserVO getUser(@PathVariable Long id) { UserPO po = userService.getById(id); return new UserVO(po.getId(), po.getName(), po.getAvatar()); }

这一层抽象,隔离了内部模型和外部契约,让前后端可以独立演进。

3.3 设计模式中的抽象:23 种模式几乎都在讲抽象

  • 策略模式:将算法抽象成接口,运行时替换

  • 工厂模式:将对象创建过程抽象,客户端不关心具体类

  • 适配器模式:将不兼容的接口抽象成统一的调用方式

  • 代理模式:在不修改原始类的情况下,抽象出额外的控制逻辑(如 Spring AOP)

3.4 分层架构:宏观层面的抽象

三层架构(Controller/Service/DAO)就是一种抽象:

  • Controller 层抽象了 HTTP 请求的处理方式

  • Service 层抽象了业务逻辑的核心流程

  • DAO 层抽象了数据存储的细节

每一层只关心它需要知道的,不关心下层具体怎么实现。这就是关注点分离

四、抽象思想的更高层次:从代码到架构

4.1 微服务中的抽象边界

微服务拆分本质上是在做领域抽象:哪些功能应该放在一起(高内聚),哪些应该隔离开(低耦合)。一个好的微服务边界,就是一个合理的业务抽象。

比如“订单服务”抽象了订单创建、支付、查询的逻辑,而“库存服务”抽象了库存扣减、锁定的逻辑。两者通过 API 契约(也是抽象)交互,互不依赖内部实现。

4.2 领域驱动设计(DDD)中的抽象

DDD 中的聚合根、值对象、领域事件都是抽象工具。它们帮助开发者在复杂的业务逻辑中,提炼出核心的领域模型,忽略非本质的技术细节。

4.3 配置与策略的抽象

现代框架大量使用声明式配置application.yml、注解)来抽象底层实现。你写一行@Cacheable,Spring 就帮你完成了缓存逻辑的编织——你不需要知道它是用 Caffeine 还是 Redis。

五、抽象不是万能的:过度抽象的代价

抽象虽好,但过度抽象也会带来问题:

  • 过度设计:为了“可能将来会变”而做多层抽象,结果代码臃肿、难以追踪

  • 性能损耗:多层抽象可能带来额外的间接调用和方法分派开销

  • 学习成本:过度抽象的代码,新人需要花大量时间理解“这层是干什么的”

抽象的原则:只抽象那些确实会变化的部分,遵循YAGNI(You Aren't Gonna Need It)原则。Rails 之父 DHH 有一句名言:“过度抽象比重复代码更糟糕。”

六、总结:抽象能力是区分“码农”和“工程师”的关键

回到最初的问题:抽象到底是什么?

  • 在语法层面,它是abstract关键字、接口、抽象类

  • 在代码层面,它是面向接口编程、设计模式、分层架构

  • 在思想层面,它是忽略细节、聚焦本质的思维方式

一个初级开发者只会写“能跑的代码”;一个高级工程师会写“能应对变化的代码”。而抽象,就是应对变化最有力的武器。

当你下次写代码时,不妨多问自己一句:
“我这里的逻辑,哪些是核心本质,哪些是当前细节?我有没有办法把本质抽象出来,让细节可以随时替换?”

培养这种思维习惯,你就已经走在从“码农”到“工程师”的路上了。

你最近写的代码中,有没有哪一块逻辑是“写死了具体实现”,但实际上可能在未来需要替换的?如果现在让你重构,你会如何引入一层抽象?欢迎在评论区写下你的案例和设计思路。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/4/23 3:29:35

权力的本质,是他人对你的想象:神秘感,正是权力最廉价也最有效的燃料

权力的玻璃墙:为什么我们永远隔着一层看不见的距离 你有没有过这样的经历? 在公司待了三年,你连大老板的声音都没听过几次。他永远在那间关着门的独立办公室里,进出有秘书提前开路,开会只和总监以上的人说话。你对他的全部了解,来自于年会台上模糊的身影、内部邮件里的…

作者头像 李华
网站建设 2026/4/23 3:28:49

如何安全备份微信聊天记录:WeChatMsg数据本地化保存方案

如何安全备份微信聊天记录&#xff1a;WeChatMsg数据本地化保存方案 【免费下载链接】WeChatMsg 提取微信聊天记录&#xff0c;将其导出成HTML、Word、CSV文档永久保存&#xff0c;对聊天记录进行分析生成年度聊天报告 项目地址: https://gitcode.com/GitHub_Trending/we/WeC…

作者头像 李华
网站建设 2026/4/23 3:27:47

Boss-Key老板键:职场隐私保护神器,一键隐藏窗口的秘密武器

Boss-Key老板键&#xff1a;职场隐私保护神器&#xff0c;一键隐藏窗口的秘密武器 【免费下载链接】Boss-Key 老板来了&#xff1f;快用Boss-Key老板键一键隐藏静音当前窗口&#xff01;上班摸鱼必备神器 项目地址: https://gitcode.com/gh_mirrors/bo/Boss-Key 你是否经…

作者头像 李华
网站建设 2026/4/23 3:27:24

NVIDIA H200与TensorRT-LLM在AI推理中的性能突破

1. NVIDIA H200与TensorRT-LLM在MLPerf基准测试中的突破性表现生成式AI正在彻底改变人机交互的范式。从编写营销文案到生成程序代码&#xff0c;从创作数字艺术到合成视频内容&#xff0c;以大型语言模型&#xff08;LLMs&#xff09;为代表的生成式模型正在重塑各个行业的效率…

作者头像 李华
网站建设 2026/4/23 3:20:47

深度学习在脊柱健康诊断中的技术实现与应用

1. 深度学习如何重塑脊柱健康诊断脊柱侧弯和脊柱后凸等脊柱疾病影响着全球数亿人的生活质量。传统诊断依赖医生手动测量X光片上的角度和距离&#xff0c;不仅耗时耗力&#xff0c;还存在主观判断差异。我在医疗影像分析领域工作多年&#xff0c;亲眼见证了许多患者因为诊断延迟…

作者头像 李华