【抽象思想-从复杂中抽离简单、收敛的口子】

抽象 = 忽略次要细节,只保留对外必须的信息;把复杂的内部逻辑藏起来,对外暴露简单的契约

1. 接口 / 抽象类 -多态抽象

接口多态(插头):用interface语法,实现可替换实现

目的:屏蔽多个不同实现的差异,对外一套调用方式。

TypeScript 复制代码
// 抽象契约:插头规格
interface Storage {
  set(key:string, value:string):Promise<void>
  get(key:string):Promise<string|null>
}

// 不同实现,内部逻辑完全不一样,但插头一样
class RedisStorage implements Storage {}
class FileStorage implements Storage {}
class MemoryStorage implements Storage {}

上层业务只调用 storage.set(),不用管存 Redis、文件还是内存。

对应:Runner、MCP 都属于这一类抽象。

2. 函数-封装抽象(最简单、最基础的抽象)

函数抽象:用function语法,实现隐藏细节

把一堆重复的细节代码包进函数,对外只给入参返回值,隐藏内部细节,只是隐藏复杂度。

TypeScript 复制代码
// 抽象:把fetch、token、异常处理全部藏在函数内部
async function postApi(url, payload){
  const res = await fetch(url, {
    method:"POST",
    headers:{"token":localStorage.getItem("token")},
    body:JSON.stringify(payload)
  })
  if(!res.ok) throw new Error("请求失败")
  return res.json()
}

// 业务层只关心我要调用哪个接口,不用管token、http状态码细节
const data = await postApi("/api/xxx", {name:"xxx"})

隐藏内部实现细节,只暴露简单契约。

3. 数据抽象(对象 / 类,对现实概念建模)

目的:把零散的变量,打包成一个概念实体,对现实世界事物做抽象建模。

不做抽象:零散到处传参数,以及赋值

TypeScript 复制代码
// 一堆散落变量
const orderId = "O123";
const amount = 1000;
const status = "paid";
const createTime = "2026‑08‑17";

数据抽象:把现实概念「用户信息」抽象成对象 / 类

java典型的DO 实体类

java 复制代码
package com.jd.jdd.gyl.jxd.repay.dao.entity;


import com.jd.jdd.gyl.jxd.repay.domain.enums.LoanTypeEnum;
import lombok.Data;


@Data
public class CompanyUserRelationshipDO implements Serializable {

    private static final long serialVersionUID = -5420248199202692599L;

    private Integer id;

    private String pin;

    private String vendorId;

    private String companyId;

    /**
     * 1:老用户,2:新用户
     */
    private Integer userStatus;
}

Agent 里的 Memory、Skill 大量是这种抽象:把现实的 "记忆""工作经验" 建模成程序对象。

4、模块抽象(文件 / 模块,边界隔离)

模块抽象:用import/export语法,实现文件级边界隔离

把一组相关能力收敛到一个模块文件,只导出少量对外 API,内部实现全部私有。

TypeScript 复制代码
// 内部函数,模块私有,外部永远看不见
function parseMcpMessage(raw:string){/*复杂解析逻辑*/}

// 只对外暴露2个方法,这就是模块抽象
export function connectMcp(serverUrl:string){}
export function callMcpTool(toolName:string, args:object){}

5. 泛型抽象:剥离具体类型,适配多种数据

泛型抽象核心:

把「数据类型」也变成参数,代码逻辑固定,不绑定死某一种具体类型,一套逻辑处理多种类型。

✅ 缓存是非常经典的例子,但泛型的使用场景远不止缓存。

java 复制代码
// T 是类型参数,不再绑定死字符串或其他数据类型;存什么类型由调用方决定
public class Cache<T> {
    public void set(String key, T value){}
    public T get(String key){ return null; }
}

✅ JSF泛化调用

RPC/HTTP 统一返回体业务接口统一返回包装对象,不知道返回的 data 是什么实体:

(泛型只是编译期类型约束。 运行时 JSON 序列化,泛型信息会被擦除;

但写代码的时候编译器会帮你校验类型,防止你塞错对象进 data。)

java 复制代码
// =========【1、定义泛型类】泛型模板(写在公共common包,框架层)=========

@Data
public class Result<T> {
    private Integer code;
    private String msg;
    private T data; // data的类型交给调用方指定
}

Result<T> :带<T>模板定义:模板类,不是响应,是图纸

Result<T>:泛型抽象,剥离 data 的实体类型,一套模板适配全部接口响应

这里的 <T>类型占位符,只是一个符号,不知道最终是什么类型,把类型 "留空" 交给使用的人来填。

java 复制代码
// =========【2、调用/使用泛型,给T传入真实类型(业务Controller,调用方)】=========
Result<CompanyUserRelationshipDO> resp1;
Result<List<Order>> resp2;

Result<CompanyUserRelationshipDO>这就是实例化泛型, Result<CompanyUserRelationshipDO> resp1这才是最终接口响应对象(响应实例)

把真实类型 CompanyUserRelationshipDO 赋值给占位符 T

此时:T = CompanyUserRelationshipDO

data字段就变成 private CompanyUserRelationshipDO data;

调用方:

写这行代码的 Controller,就是泛型的调用方;--不确定查回来的是什么类型的数据源

java 复制代码
// Controller 声明的响应类型,Controller 是泛型的调用方,使用泛型Result模板
@GetMapping("/query/relation")
public Result<CompanyUserRelationshipDO> getRelation(){
    CompanyUserRelationshipDO entity = companyUserRelationshipMapper.selectById(123);
    // 这里返回的就是接口HTTP响应
    return Result.success(entity);
}

响应:HTTP 返回 JSON(最终对外响应报文)

java 复制代码
{
  "code":200,
  "msg":"success",
  "data": {
    "id":123,
    "pin":"xxx",
    "vendorId":"xxx"
  }
}

PS:嵌套泛型 Result<List<Order>>拆解

  • 外层 Result 的泛型 T = List<Order>
  • List 本身也是泛型,List 的泛型 E = Order

响应:

java 复制代码
{
  "code":200,
  "msg":"success",
  "data":[
    { "orderId":"O001" },
    { "orderId":"O002" }
  ]
}

✅ DAO 层通用基类

Mybatis‑Plus 的 BaseMapper<T>

CRUD 的通用逻辑固定,泛型 T 传入 DO 实体类型,这也是泛型抽象。

java 复制代码
// BaseMapper内置selectById、insert、delete,T代表数据库实体DO
public interface BaseMapper<T> {
    T selectById(Long id);
    int insert(T entity);
}

//你的DO直接继承,不用重复写CRUD方法
public interface CompanyUserRelationshipMapper extends BaseMapper<CompanyUserRelationshipDO> {
}

6. 中间件抽象(Web、Agent 框架大量使用)

把处理流程抽象,把主逻辑和附加逻辑做隔离。 比如 Express/Koa、LangChain Callback 中间件。

请求 → 日志中间件鉴权中间件业务主逻辑响应

主业务逻辑完全不需要写日志、鉴权代码;附加能力被抽象抽离。

Agent Runner 内部的回调钩子、日志、超时拦截,就是中间件抽象。

7. 配置驱动抽象

把逻辑变成配置,代码不改动将业务规则抽象为配置文件,不需要修改代码,改配置即可改变行为。

skill.yaml

TypeScript 复制代码
name:故障排查
max_step: 8
rules:
  - 优先查日志
  - 失败最多重试2次

代码读取配置驱动执行,业务规则和代码解耦。 Agent 的 Skill 大多就是这种抽象,把业务经验抽象成配置。

相关推荐
captain3761 小时前
多线程单例模式
java·单例模式·java-ee
martindelophy1 小时前
Codex Chrome 插件 + Timeline Studio:构建可编辑的 AI 视频剪辑 Agent 工作流
前端·人工智能·chrome
xiaotianyuanma1 小时前
【计算机毕业设计】基于Spring Boot的体育馆预约系统的设计与实现
java·spring boot·课程设计
何以解忧,唯有..1 小时前
MySQL 索引分类与底层原理深度剖析
java
whyutianict_vv2 小时前
从 Web 前端到 HarmonyOS ArkTS:一次 AI 鸿蒙全栈智能体开发的迁移实录
前端·人工智能·harmonyos
水无痕simon2 小时前
6、六大工作模式-2
java·rabbitmq
qziovv2 小时前
前端转flutter——项目架构、初始化
前端·flutter
2601_963870212 小时前
【计算机毕业设计】基于Spring Boot的非遗文创产品交易平台的设计与实现
java·spring boot·后端
lv__pf2 小时前
Spring之AOP底层源码解析(下)【TL spring14】
java·后端·spring