新闻详情

新闻详情

首页 / 资讯中心 / 详情

建造者模式全面解析:从复杂对象构建到源码实战与面试考点

发布时间:2026/9/30 21:09:27来源:尧图网络
建造者模式全面解析:从复杂对象构建到源码实战与面试考点
作为后端开发写业务代码时最烦的是什么我估计很多人都会说new 一个字段特别多的对象。订单、用户、商品详情、报表配置……光构造函数就能写满一屏。更难受的是这种代码改起来也累今天加一个字段明天调整一下参数顺序所有调用方都要跟着遭殃。设计模式里的建造者模式Builder Pattern就是为了治这个病来的。它是创建型设计模式里出场率非常高的一个套路核心思想是把一个复杂对象的构建过程和它的最终表现拆开让同一个构建流程可以产出不同的对象。这篇文章我会从零开始把建造者模式要解决的问题、四个角色的分工、手写代码、源码中的实际应用、面试软考高频考点一次说清适合刚开始学设计模式的人也适合正在准备软考或技术面试、想弄懂建造者和工厂模式区别的朋友。1. 从“构造函数爆炸”说起建造者模式要解决的三个具体麻烦1.1 十几个参数的构造函数调用方真的能分清吗先看下面这个订单类代码不长但已经能闻到坏味道public class Order { private long orderId; private long userId; private String receiverName; private String receiverPhone; private String receiverAddress; private String paymentMethod; private String remark; public Order(long orderId, long userId, String receiverName, String receiverPhone, String receiverAddress, String paymentMethod, String remark) { this.orderId orderId; this.userId userId; this.receiverName receiverName; this.receiverPhone receiverPhone; this.receiverAddress receiverAddress; this.paymentMethod paymentMethod; this.remark remark; } }调用方的画风是这样的new Order(1001L, 2088L, 张三, 13800000000, 北京市海淀区中关村大街1号, WECHAT, 尽快发货);如果你是第一次接手这段代码看到那两个字符串参数能分清哪个是手机号、哪个是地址吗第三个字符串是支付方式还是备注大概率是分不清的。全参构造方法的第一个问题叫“参数顺序地狱”——编译器只检查类型不检查语义。一旦谁手滑把手机号和地址传反了不会编译报错等用户收不到货你才从线上日志里发现。第二个问题是它完全不可扩展明天产品说加一个“发票抬头”字段全参构造方法就得改所有调用方也得跟着改。第三个问题更难缠当构造方法重载越来越多代码会迅速膨胀到没法维护。1.2 有些对象不是 new 一下就能用的除了参数多还有一类对象在构建时天然带“步骤”。比如生成一份报表先创建报表骨架再填充标题和目录然后按顺序插入各章节数据最后统一加水印和页脚。再比如组装电脑先装 CPU再插内存然后装显卡最后装系统。这种对象不是“给参数就完事”它的构建过程本身是有顺序、有分支的。如果把这一整套步骤都写进构造方法代码就会变成一个几百行的大杂烩既要管步骤A又要管步骤B还要处理不同版本的差异。更麻烦的是需求一变整个构造方法被改得面目全非。这其实违背了面向对象设计里一个基本思想把“做什么”和“怎么做”分开。上层调用者只需要知道“我要一个订单”至于这个订单是走普通流程、还是要附赠小卡片不应该由构造方法一揽子承担。1.3 建造者模式的核心定义建造者模式的定义是“将一个复杂对象的构建与它的表示分离使得同样的构建过程可以创建不同的表示。”这句话听起来很绕用流水线来类比就好懂了。一条组装流水线它的动作顺序是固定的放料、压合、喷涂、质检。但你换一个模具就能产出完全不同的产品。流水线是“构建过程”模具是“具体实现”最终产品是“表示”。所以建造者模式真正做的事是把构建步骤抽象成接口把每种具体实现放进不同的“建造者”类里再把“按什么顺序调用这些步骤”的控制逻辑放进“指挥者”类。这样一来新增一种产品只需要新增一个建造者类不用动流水线也不用动其他建造者。2. 四个角色一次讲清楚以组装电脑为例建造者模式一共有四个经典角色我每次给团队里刚入门的人讲的时候都用“组装电脑”这个例子理解起来最快比直接贴 UML 图好用得多。2.1 Product你要的那个复杂对象Product 就是最终要创建出来的那个复杂对象。在组装电脑的例子中它就是 Computer 类属性包括 CPU、内存、硬盘、显卡、操作系统等。Product 通常字段很多而且很多字段是“可选项”或者“有默认值”的。比如办公机不配独立显卡游戏机必须上独立显卡。Product 还有一个特点在经典写法里它的字段往往没有 setter只提供 getter。这样做是为了让对象在构建完成后保持稳定避免外部代码在运行时随便修改它的内部状态。这个“构建完就锁死”的设计在后面讲实战坑的时候还会再提到。2.2 Builder 接口与 ConcreteBuilder步骤的约定与落地Builder 是一个抽象接口它规定了构建产品的“步骤”。在电脑例子里Builder 接口大概长这样buildCpu()、buildMemory()、buildDisk()、buildGraphicsCard()、buildOs()。这些方法只声明“要做什么”不关心“具体怎么做”。记住这些步骤的名字本身就是一种文档比看构造函数那一堆参数直观得多。ConcreteBuilder 是 Builder 接口的具体实现。GameComputerBuilder 会往 Computer 里塞 i9-14900K、64G 内存、RTX 4090OfficeComputerBuilder 可能只塞 i5、16G 内存和核显。它们都实现同一个接口但产出完全不同。这就是定义里说的“同样的构建过程可以创建不同的表示”。后面手写订单实战里你会看到同样的接口、同样的步骤不同的具体建造者就能造出不同形态的对象。2.3 Director安排流程的“工头”Director 是新手最容易忽略的角色但它是经典建造者模式的灵魂。Director 不关心具体硬件它只负责一件事确认调用的顺序。比如它规定“组装电脑”必须按 CPU、内存、硬盘、显卡、系统的顺序来就永远按这个顺序调 builder 的方法。这就带来两个好处第一如果某个步骤必须前置Director 能保证不写乱第二调用方不需要知道构建顺序只要告诉 Director“我要一台游戏机”Director 就去指挥对应的具体建造者干活。正是因为 Director 存在“构建过程”和“具体实现”才真正被解耦。如果你不用 Director这种流程控制逻辑就只能散落在各个调用方代码里今天这里调错顺序、明天那里少一步问题会接踵而至。2.4 角色关系速查表角色在本例中的存在核心职责ProductComputer被构建的复杂对象字段多、通常不可变BuilderComputerBuilder 接口声明构建步骤不关心实现ConcreteBuilderGameComputerBuilder / OfficeComputerBuilder实现每一步决定最终产品的具体配置DirectorComputerDirector控制步骤调用顺序和流程规则一句话记住这四个角色Product 是房子Builder 是施工标准ConcreteBuilder 是施工队Director 是监工。有监工在施工队不能乱来换一支施工队房子风格就变了。这个类比在面试里也特别好用你只要把四个角色往这个框架里一套代码里谁是干什么的立刻清楚了。3. 手写一个订单对象的完整实战理论讲完直接上手写代码。我以一个真实业务里最常见的“订单对象”为例按经典 GoF 风格实现完整版本。别嫌类多先把完整形态看明白后面再聊怎么简化。3.1 需求设定假设 Order 的字段如下orderId 和 userId 是必填项receiverName、receiverPhone、receiverAddress 是收货信息允许为空paymentMethod 有默认值默认“货到付款”remark 默认空字符串。我们还希望 Order 被构建出来后是不可变对象也就是没有 setter所有字段都是 final外部只能读不能改。这样既能避免“对象构建到一半被别人改坏”的问题也方便后续在多线程场景里安全共享。3.2 经典 GoF 风格代码实现先写产品类 Orderpublic class Order { private final long orderId; private final long userId; private final String receiverName; private final String receiverPhone; private final String receiverAddress; private final String paymentMethod; private final String remark; private Order(OrderBuilder builder) { this.orderId builder.orderId; this.userId builder.userId; this.receiverName builder.receiverName; this.receiverPhone builder.receiverPhone; this.receiverAddress builder.receiverAddress; this.paymentMethod builder.paymentMethod; this.remark builder.remark; } public long getOrderId() { return orderId; } public long getUserId() { return userId; } public String getReceiverName() { return receiverName; } // 其余 getter 省略 }注意两个细节构造函数是 private 的外部不能直接 new OrderOrder 接收的是 OrderBuilder 对象从 Builder 身上取值完成初始化。再写抽象建造者接口public interface OrderBuilder { OrderBuilder receiverName(String name); OrderBuilder receiverPhone(String phone); OrderBuilder receiverAddress(String address); OrderBuilder paymentMethod(String method); OrderBuilder remark(String remark); Order build(); }然后写具体建造者public class ConcreteOrderBuilder implements OrderBuilder { private final long orderId; private final long userId; private String receiverName ; private String receiverPhone ; private String receiverAddress ; private String paymentMethod CASH_ON_DELIVERY; private String remark ; public ConcreteOrderBuilder(long orderId, long userId) { this.orderId orderId; this.userId userId; } Override public OrderBuilder receiverName(String name) { this.receiverName name; return this; } Override public OrderBuilder receiverPhone(String phone) { this.receiverPhone phone; return this; } Override public OrderBuilder receiverAddress(String address) { this.receiverAddress address; return this; } Override public OrderBuilder paymentMethod(String method) { this.paymentMethod method; return this; } Override public OrderBuilder remark(String remark) { this.remark remark; return this; } Override public Order build() { if (orderId 0 || userId 0) { throw new IllegalArgumentException(orderId 和 userId 为必填项); } return new Order(this); } }最后是 Directorpublic class OrderDirector { public Order buildStandardOrder(long orderId, long userId, String name, String phone, String address) { OrderBuilder builder new ConcreteOrderBuilder(orderId, userId); return builder.receiverName(name) .receiverPhone(phone) .receiverAddress(address) .paymentMethod(WECHAT_PAY) .build(); } public Order buildGiftOrder(long orderId, long userId, String cardText) { OrderBuilder builder new ConcreteOrderBuilder(orderId, userId); return builder.remark(cardText) .build(); } }使用侧代码OrderDirector director new OrderDirector(); Order order director.buildStandardOrder(1001L, 2088L, 张三, 13800000000, 北京市海淀区...);这段代码量不少但结构很清楚Order 不需要暴露 setter调用方也不直接碰具体建造者一切都由 Director 安排好了。你以后在这里加“赠品订单”“加急订单”之类的流程只需要往 Director 里加方法产品类和建造者类都不用动。3.3 去掉 Director直接让客户端指挥 Builder经典写法里 Director 很重要但在真实项目里我发现很多人会把 Director 去掉让客户端直接操作 Builder。也没问题。尤其是构建步骤只有两三个、顺序不容易出错时加一个 Director 反而显得仪式感过重。去掉 Director 后的调用方式就是这样客户端自己把链式调用串起来Order order new ConcreteOrderBuilder(1001L, 2088L) .receiverName(张三) .receiverPhone(13800000000) .receiverAddress(北京市海淀区中关村大街1号) .paymentMethod(WECHAT_PAY) .build();这样的代码可读性非常好每一行都在告诉阅读者“我在给这个订单配置什么”比全参构造函数的十个参数直观太多。代价是如果多处地方都在创建订单每处都要重复写一遍链式调用。所以我的建议是如果只有一两个地方创建对象直接用链式 Builder 就行如果有一组固定的创建套路比如所有普通订单都要走同一个流程就把套路收进 Director避免重复代码散落各处。3.4 这段代码为什么能工作从使用侧看模式价值现在回头再看建造者模式的价值其实体现在三个地方。第一调用方不会因为参数太多而犯错每一步都有方法名提示可读性有了质的提升。第二产品的构建过程可以被复用——Director 里 buildStandardOrder 被十个业务方调用它就硬生生省掉了十份重复代码。第三Order 被构建出来后不可变所有字段都是 final不会有中间状态这种对象在并发环境下也更好用。提示经典建造者模式里的“不可变对象”不是强制要求但强烈推荐。如果你设计的产品类允许外部随意 set那么建造者模式最大的优势——构建过程安全稳定——就丢了一半。4. 你天天在用的建造者框架源码里的影子很多人觉得设计模式是书本里的东西实际项目用不上。其实恰恰相反建造者模式是你每天都在用的只是没注意而已。4.1 StringBuilder最朴素的建造者Java 里有一个几乎人人都用过、但很少有人意识到它是建造者模式的类StringBuilder。你写字符串拼接时是不是这样的StringBuilder sb new StringBuilder(); sb.append(用户).append(userName) .append(订单号).append(orderId) .append(金额).append(amount); String message sb.toString();append 方法返回的是 StringBuilder 自身所以才能一直点下去toString 返回最终拼接出的字符串就相当于 build 方法。这里没有抽象 Builder 接口也没有 Director属于最朴素的“自建自用”风格。为什么 JDK 要这么设计因为 String 是不可变的如果每次都直接拼接字符串会产生大量中间对象而 StringBuilder 相当于一个可变的“施工场地”在施工场地里反复修改内容最后一次性交付一个完整的 String性能和写法都兼顾了。4.2 Lombok Builder注解帮你生成建造者Java 项目里最常用的简化方式就是 Lombok 的 Builder 注解。你只需要写Builder public class User { private Long id; private String name; private Integer age; }编译后 Lombok 会自动给你生成一个静态方法 builder() 和一套链式方法使用侧长这样User user User.builder() .id(1L) .name(张三) .age(20) .build();这种方式的本质是简化版建造者没有抽象 Builder 接口没有多个 ConcreteBuilder也没有 Director只有产品类内部嵌套的一个静态 Builder。它解决的是“参数语义不清”的问题但放弃的是“不同构建过程复用同一套流程”的灵活性。如果你只是嫌构造器难看用 Builder 是最快的如果你的构建流程本身很复杂那就得回归经典写法。另外要注意用 Builder 时要配合 Builder.Default 处理默认值否则字段默认值会被置成 null这一点很多人踩过坑。4.3 OkHttp 的 Request.Builder链式调用的范本做网络请求的人对 OkHttp 一定不陌生它的 Request 就是用 Builder 创建的。典型用法Request request new Request.Builder() .url(https://api.example.com/order/1001) .header(Authorization, Bearer xxx) .method(GET, null) .build();这里有个很关键的细节url() 是必填的其他大多是可选的。OkHttp 怎么保证必填项没漏它在 build() 方法里做了校验url 为空就抛出 IllegalStateException提示你“url null”。这是建造者模式里一个非常重要的设计点正因为 Builder 把“设置属性”和“最终校验”分开了你才能把所有必填项的检查集中放在 build() 方法里。如果像传统构造器一样校验逻辑就只能塞在构造方法里一旦参数多起来会非常混乱。这个“build 时统一校验”的思路建议你也用在自己写的 Builder 里。4.4 看到 Builder 类时的识别套路读开源项目时我一般靠三个特征快速识别是不是建造者模式类内部或者旁边有一个叫 Builder 的静态内部类Builder 里有一堆和产品字段同名的方法而且大多数方法返回值都是 Builder 本身最后总会有一个 build() 或 buildXxx() 方法返回真正的产品对象。只要看到这三个特征哪怕代码写得再花哨你也能判断它底层是建造者模式。这个识别套路在面试、阅读源码、甚至排查别人写的烂代码时都很管用。很多框架的配置对象、HTTP 客户端、ORM 查询构造器用的全是这个套路。5. 建造者的三种主流变体以及和工厂模式的边界我接触到的建造者模式实际有至少三种长相不要再以为设计模式只有书里那一种标准图了。5.1 GoF 经典风、简化风、链式风第一种是 GoF 书里的经典四角色Product、Builder、ConcreteBuilder、Director 一个不少适合特别重视构建步骤顺序的场景比如组装流程、报表生成、复杂配置装配。第二种是简化风去掉 Director 和抽象接口只保留具体 Builder客户端直接指挥。第三种就是链式风在简化风的基础上每个 set 方法返回自己用链式调用把代码写得很简短。三者没有绝对优劣本质是“模式严谨程度”和“代码简洁程度”的博弈。变体包含角色适用场景优点缺点GoF 经典风Product Builder ConcreteBuilder Director构建步骤多、顺序固定、有多个产品变体流程复用、可扩展性最强类多前期代码量大简化风Product ConcreteBuilder字段多但步骤简单代码量适中固定流程无法复用链式风Product 静态内部 Builder字段多的普通实体写起来最爽可读性好没有流程控制只解决参数语义问题在真实项目里后两种出现的频率远高于第一种。所以学习时不要只背 GoF 的图得先知道日常代码里遇到的绝大多数 Builder 其实都是简化版或链式版。5.2 链式调用为什么能串起来return this 的秘密很多人第一次看链式调用时疑惑为什么每个方法后面还能再点一个点答案很简单因为每一步方法的返回值都是当前 Builder 对象自己。写一个最简单的例子public class DemoBuilder { private String name; public DemoBuilder name(String name) { this.name name; return this; } public String build() { return name name; } }调用时就会变成String result new DemoBuilder().name(张三).build();.name(张三) 返回 DemoBuilder 类型的 this所以后面又可以接 .build()。链式调用的本质就是“返回自身”这个技巧不仅建造者模式能用很多 Fluent API 设计里也在用。理解了这一点你就不会再对链式代码感到神秘了。不过要小心有些新手会把 return this 写成 return new DemoBuilder()那样每一步都会创建一个新对象前一步设置的值全部丢失最后 build 出来一看全是默认值。5.3 建造者模式 vs 工厂模式面试必答题面试和软考里最常问的问题之一就是“建造者模式和工厂模式有什么区别”。我知道很多人会背答案但真正理解以后你会明白它俩根本不在一个维度上。工厂模式关心的是“创建什么产品”你告诉工厂“给我一个汉堡”工厂直接返回一个做好的汉堡至于这个汉堡是怎么一步步做的工厂不关心。建造者模式关心的是“怎么创建产品”你盯着店员说“面包、加牛肉饼、加生菜、加沙拉酱”一步步指挥最后拿到一个按你要求做出来的汉堡。用一个例子帮助记忆同样是造一辆汽车工厂模式是一个方法 createCar() 直接返回整车建造者模式是 builder.setEngine()、builder.setWheels()、builder.setBody()最后 build() 拼起来。所以在实际选型时如果产品就是“一个大对象没什么步骤”用工厂或直接构造器就够了如果产品“构造分多个步骤而且不同步骤可能有不同组合”才用建造者。这也是为什么建造者通常和“不可变对象”“复杂对象”绑定出现。5.4 必填项与默认值用校验管住乱传参建造者模式用多了以后你一定会遇到一个问题必填字段和可选字段怎么处理我教大家一个简单可靠的三步法。第一步在 Builder 的构造函数里接收必填项比如前面订单例子的 orderId 和 userId通过 new ConcreteOrderBuilder(orderId, userId) 传进去这样想漏传都难。第二步可选字段在 Builder 里给默认值这样调用方不设置也能得到合理结果。第三步最后在 build() 方法里统一做校验发现必填项不合法就抛出异常。这样做的好处是校验逻辑集中、调用方式灵活、错误能被尽早发现而不是等到对象用起来才在某个深层方法里炸一个空指针。不要依赖构造方法重载来区分选填参数那是旧时代的老办法字段一多就崩。6. 考试、面试和实战中的高频坑6.1 软考/期末怎么考角色识别与 UML 题软考中级、高级的设计模式题经常这样出给你一段 Java/C 代码问你它属于哪种设计模式或者给出一个 UML 类图让你补全角色。遇到这种题识别的关键就三个有没有 Builder 接口或抽象类有没有多个 ConcreteBuilder有没有一个 Director 在统一调用构建步骤如果三者都有那就是标准的建造者模式。如果只有一个 Builder 类、没有 Director那就要看它是不是“简化版建造者”代码里如果存在分步设置属性再 build 的结构依然应该往建造者上靠。软考还有一个常见对比题就是建造者模式和抽象工厂模式的区别。记住一句话就够了抽象工厂关注“一系列相关产品”怎么创建强调产品族整体替换建造者关注“一个复杂产品”的构建步骤强调逐步组装。另外软考喜欢问“哪个角色对产品构建过程最了解”答案是 Director因为它掌握流程顺序而 ConcreteBuilder 只负责具体某一步的实现。这几个考点反复出现你得当心。6.2 实战坑1过度设计说了这么多好话我也得泼一盆冷水建造者模式很容易被当成“银弹”滥用。我见过有人给只有三个字段的小实体也套一个 Builder还硬生生写了一个 Director最后类数量翻了一倍代码可读性不升反降。过度设计的本质是你用一把重武器去杀一只鸡反而把自己的手压酸了。我给自己定的判断标准是这样的对象字段少于 4 个直接写构造器或静态工厂字段 4 到 8 个推荐用 Lombok Builder 或手写简化版 Builder字段超过 8 个而且构建步骤还有顺序要求、存在多种产品变体才考虑上经典四角色。换句话说建造者的价值是随着字段数量和流程复杂度的增长而增长的不是所有创建型问题都该由它来解。如果你发现自己写出来的 Builder 比产品类还长而且没有第二步扩展计划先停一下大概率是过度设计了。6.3 实战坑2不可变对象和空指针建造者模式最常见的线上故障就是“对象某些字段是 null”。原因通常是 Builder 里没有给默认值调用方漏设了一个可选字段产品对象构建成功后拿着 null 到处用最后在一个深层方法里报空指针。要避免这个坑我有两条经验一条是给所有可选字段都设置合理的默认值比如集合用空集合而不是 null字符串用空串而不是 null另一条是在 build() 方法里做集中校验发现非法组合直接抛出带清晰提示的异常把问题扼杀在构建阶段而不是留到运行时再追踪。这里又牵扯到“不可变对象”的一个好处因为产品对象没有 setter所有字段都必须在构建阶段确定所以构建是唯一一个能全面校验的时机。如果你贪方便写了大量 setter那别人可以在构建完成后把某字段改成 null你的校验就形同虚设了。所以我在团队里通常约定既然用了建造者模式产品类就尽量做成不可变类别半途而废。6.4 实战坑3多线程安全与每次新建 Builder最后一个坑是关于线程安全的。Builder 本身是有状态的它内部存了一堆字段链式方法每调用一次就会修改状态。如果同一个 Builder 实例同时被多个线程调用比如一个线程调 receiverName()另一个线程调 paymentMethod()最后两个线程再各自 build()那么拿到的产品字段可能是互相穿插的结果完全不可预估。所以 Builder 设计成“一次性使用”每次要构建对象都 new 一个 Builder 实例不要在多个线程之间共享同一个实例。如果你确实需要复用配置可以把 Builder 创建之后作为“模板”拷贝一份或者干脆在方法内部用 builder() 工厂方法每次生成新的 Builder。多线程下要构造复杂对象还有一个替代方案是先构建一个不可变的产品模板再用拷贝替换字段的方式生成新对象但这已经超出建造者模式本身的讨论范围了。一句话总结Builder 请用完就扔别留着共享。写到这里建造者模式从理论到实战差不多讲全了。我最后再交代一点个人的使用体会其实我并不主张在任何项目里都全套照搬 GoF 的四角色结构更多时候我会把它拆开用——字段多、要求可读性强的场景上链式 Builder流程固定、需要复用的场景再补一个类似 Director 的封装方法。如果你用的是 Lombok 项目先确认团队成员都看得懂 Builder 生成的代码不然手写一个三十行的 Builder 类反而更稳。设计模式的价值不在于“用了哪个模式”这件事本身而在于它能不能帮你把代码结构变得更清楚。等你哪天写代码时下意识知道“这个问题用建造者合适、那个问题用工厂更顺”那才算是真正学会了。
网站建设高端定制企业官网
RELATED

相关资讯

更多精彩内容,欢迎继续阅读

较早相关资讯

最新相关资讯

2026.1.9:VSCode集成claude插件完美方案,把settings.json改到TaoToken,用Kimi K2计费 2026/9/30 21:57:33

2026.1.9:VSCode集成claude插件完美方案,把settings.json改到TaoToken,用Kimi K2计费

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

阅读更多 →
把论文里的数据,画成一眼能懂的图 2026/9/30 21:56:22

把论文里的数据,画成一眼能懂的图

凌晨一点,论文正文已经写到讨论部分,真正卡住人的却不是文字,而是一张图:实验数据放进去之后,到底该用柱状图、折线图,还是散点图?图做得太简单,结论不突出;图做得太复杂…

阅读更多 →
第7章:RAGFlow Chat 助手创建与提示词配置 2026/9/30 21:55:56

第7章:RAGFlow Chat 助手创建与提示词配置

1 项目背景 业务场景 HR 制度问答机器人上线一个月后,「云帆科技」的不同部门开始提需求了。财务部说:"我们的报销制度能不能也搞个问答?"行政部说:“办公用品申领流程能不能也接进去?“但每个部门对机器人…

阅读更多 →
TikTok数据分析工具怎么选?6款定价实测+TaoToken配置CLI/MCP接入 2026/9/30 21:55:50

TikTok数据分析工具怎么选?6款定价实测+TaoToken配置CLI/MCP接入

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

阅读更多 →
宿舍夜谈:金融专硕论文查重翻车之后 2026/9/30 21:54:57

宿舍夜谈:金融专硕论文查重翻车之后

周五晚上十点半,研究生宿舍。金融专硕的林晚刚把论文初稿查了个重,坐在椅子上不动。同门的师姐陈希推门进来。 陈希:脸这么垮,查重爆了? 林晚:38%。导师限两周降到 10% 以内。师姐,我大半年都耗…

阅读更多 →
RK3588为何砍掉原生LVDS?显示接口演进与MIPI DSI桥接方案解析 2026/9/30 21:54:57

RK3588为何砍掉原生LVDS?显示接口演进与MIPI DSI桥接方案解析

1. 从一块点不亮的屏说起:RK3588 的 LVDS 到底去哪了 第一次在 RK3588 上接一块老款 10.1 寸工业屏的时候,我盯着原理图找了半天,愣是没找到 LVDS 那几对差分线。板子上明明印着 MIPI DSI 的丝印,屏却是 LVDS 接口的,这…

阅读更多 →

今日资讯

本周资讯

本月资讯

看完文章仍有疑问?

联系尧图顾问,获取一对一建站咨询

立即免费咨询 📞 400-888-8888
📞 ✉