行为型设计模式详解:策略、模板方法、观察者、迭代器、责任链
设计模式系列写到第四篇终于轮到行为型模式了。前几篇我们把创建型怎么把对象造出来和结构型怎么把对象组合起来讲完了这一篇开始讲行为型模式的“上篇”。如果你是跟着这个系列一路看过来的应该已经感受到一个规律创建型模式关注的是“对象的诞生”结构型模式关注的是“对象的静态关系”。而行为型模式完全不同它关注的是对象之间在运行时怎么协作、怎么分配责任、怎么通信。换句话说前两类模式回答的是“对象长什么样”行为型模式回答的是“对象在一起怎么干活”。行为型模式一共有11个数量是所有类别里最多的。一口气全讲完既不现实也容易消化不良。这篇我先把其中5个最常见、面试和日常开发里出现频率最高的讲清楚策略模式、模板方法模式、观察者模式、迭代器模式、责任链模式。剩下的状态模式、命令模式、备忘录模式、访问者模式、中介者模式、解释器模式放到下篇继续。每个模式我会按照“解决了什么问题 → 代码怎么落地 → 实战中要注意什么”的顺序来讲尽量把我在实际项目里踩过的坑、用过的变体写法都交代清楚。不管是刚开始学设计模式的新人还是想快速回顾的老手这篇都适合你。1. 先搞清楚行为型模式到底在解决什么问题1.1 从“对象怎么搭”到“对象怎么协作”前面说的创建型和结构型模式本质上都是在解决静态结构问题——类和类之间怎么继承、怎么组合、怎么代理。这些关系在你把代码写完的那一刻就已经确定了。行为型模式不一样。它关注的是动态行为——程序运行过程中对象之间怎么传递消息、怎么分配职责、怎么互相调用。同一个对象在不同策略下表现不同同一个请求在不同处理器链上走向不同。这些都是在运行时才决定的。我打个比方。创建型模式像生产线设计——决定零件怎么生产结构型模式像装配图——决定零件怎么拼装行为型模式则是流水线上的调度规则——决定了每个工位什么时候动作、做完之后传给谁、遇到异常怎么办。1.2 行为型模式的“两条主线”11个行为型模式其实可以分成两类理解了这个分类学习成本能降低一半第一类算法与行为的封装这类模式的核心思想是把“变化的算法/行为”从“稳定的主体”中抽离出来。代表有策略模式把一个算法的不同实现封装成独立的策略对象模板方法模式把算法的骨架定死把可变的步骤留给子类状态模式把对象在不同状态下的行为封装成独立的状态对象命令模式把一次请求/操作封装成一个独立对象第二类对象间的通信与职责分配这类模式的核心思想是解决“对象之间怎么说话、谁该干活”的问题。代表有观察者模式一对多的依赖通知责任链模式请求沿着链传递找到能处理的人迭代器模式提供统一遍历方式屏蔽内部结构中介者模式通过中介对象转发多方通信访问者模式在不修改对象结构的前提下增加新操作这两条主线下面写代码时思路是完全不同的。封装类的主线你得多考虑“哪些是稳定的、哪些是变化的”通信类的主线你得多考虑“谁通知谁、谁处理谁、顺序是什么”。理解了这两条线接下来每个模式看起来都不会觉得是孤立的能串成一个体系。2. 策略模式把“怎么做”从“做什么”手里拿过来2.1 一个支付场景的演化过程策略模式是我在实际项目中用得最多的行为型模式。我们还是拿一个真实的业务场景来说——订单支付。假设某电商项目一开始只有一个余额支付渠道代码很简单public class PaymentService { public boolean pay(OrderInfo order) { // 从账户余额扣款 return balanceService.deduct(order.getUserId(), order.getAmount()); } }第二天产品经理来了要接入银行网关支付。于是代码变成public class PaymentService { public boolean pay(OrderInfo order, PayChannel channel) { if (channel PayChannel.BALANCE) { return balanceService.deduct(...); } else if (channel PayChannel.BANK) { return bankGateway.pay(...); } return false; } }第三天又来了扫码支付、第三方支付……这个else if链越来越长。你心里已经开始发毛了新增一个渠道就要改一次PaymentService测试要回归所有渠道而且万一某个渠道的服务注入方式还不一样这个类会膨胀到没法维护。这不是“代码洁癖”这是典型的扩展点被埋没问题。支付逻辑的主体流程是稳定的——验证订单、调用渠道、记录结果。变化的是“具体调哪个渠道、渠道内部怎么走”。把变化封装起来这就是策略模式的核心思路。2.2 策略模式的标准结构策略模式有三个角色策略接口定义算法族共有的行为具体策略实现接口每种算法一个类上下文持有策略引用调用方只需面向接口操作对应到支付场景代码长这样// 策略接口 public interface PayStrategy { boolean pay(OrderInfo order); } // 具体策略余额支付 public class BalancePayStrategy implements PayStrategy { Override public boolean pay(OrderInfo order) { // 扣减余额、记流水 return true; } } // 具体策略扫码支付 public class QrPayStrategy implements PayStrategy { Override public boolean pay(OrderInfo order) { // 调用扫码支付网关 return true; } } // 具体策略银行卡支付 public class BankPayStrategy implements PayStrategy { Override public boolean pay(OrderInfo order) { // 调用银行接口 return true; } }上下文类不再关心具体策略只面向PayStrategy编程public class PaymentService { private PayStrategy strategy; public void setStrategy(PayStrategy strategy) { this.strategy strategy; } public boolean execute(OrderInfo order) { return strategy.pay(order); } }客户端选择策略的职责通常交给工厂或者配置中心而不是让PaymentService自己判断。PayStrategy strategy PayStrategyFactory.getStrategy(order.getChannel()); paymentService.setStrategy(strategy); paymentService.execute(order);这套结构写完之后新增支付渠道只需要做两件事写一个实现PayStrategy的新类在工厂里注册一下。开闭原则立刻就体现了——对扩展开放对修改关闭。2.3 我把过的两个坑第一个坑把所有判断都塞进工厂策略模式最容易被反向滥用。有人把所有渠道的构建逻辑都堆到工厂里导致工厂本身变成了一个巨大的if/else。解决思路是让工厂从配置中心读取“渠道类型 - 策略Bean名称”的映射用反射或者注册表来创建策略对象。第二个坑策略对象内部还是有大量公共代码不同支付策略其实有很多共同的流程比如订单状态校验、失败重试、流水记录。如果每个策略类都各自写一遍就会出现大量重复代码。我的做法是写一个抽象基类把公共流程放在基类把差异逻辑留在子类。但注意这已经是在往模板方法模式靠了。所以策略模式和模板方法模式经常一起出现——策略接口定边界抽象基类定公共流程具体子类实现差异。3. 模板方法模式算法骨架与可变步骤的分离3.1 用“冲泡饮料”理解模板方法如果说策略模式是把“整个算法”封装成对象那么模板方法模式则是把算法的骨架定死在父类里把可变步骤留给子类重写。我经常用“冲泡饮料”来给学生讲这个模式不管泡咖啡还是泡茶流程都是一样的——烧水、冲泡、加料倒杯。但是具体冲泡什么、加什么料每一步都不一样。把不变的骨架写在父类把变化的步骤留给子类这就是模板方法模式。放到订单处理的场景里稳定的骨架校验订单 → 扣减库存 → 记录快照 → 通知客户可变的步骤不同订单类型校验规则不同、扣库存策略不同3.2 模板方法 钩子方法的实际写法public abstract class AbstractOrderProcessor { // 模板方法定义算法骨架建议用 final 防止子类篡改 public final void processOrder(OrderInfo order) { validate(order); deductStock(order); if (needNotify(order)) { // 钩子方法子类可选覆盖 notifyCustomer(order); } createSnapshot(order); } // 抽象步骤强制子类实现 protected abstract void validate(OrderInfo order); // 抽象步骤 protected abstract void deductStock(OrderInfo order); // 钩子方法默认实现子类不一定重写 protected boolean needNotify(OrderInfo order) { return true; } private void notifyCustomer(OrderInfo order) { // 发送短信/站内信 } private void createSnapshot(OrderInfo order) { // 保存订单快照到审计表 } }子类只需要关注自己那部分差异public class FlashSaleOrderProcessor extends AbstractOrderProcessor { Override protected void validate(OrderInfo order) { // 限购校验、活动时间校验 } Override protected void deductStock(OrderInfo order) { // 锁定活动库存 } Override protected boolean needNotify(OrderInfo order) { // 秒杀订单不发送消息避免轰炸 return false; } }这里有个关键点processOrder用了final修饰。很多人忽略这个细节导致子类把整个骨架都重写了模板方法模式就失去了意义。骨架是约定约定就不能被破坏。3.3 模板方法 vs 策略模式到底怎么选这是面试里很爱问的一个对比也是实际开发里我经常要做的选择。对比项模板方法模式策略模式复用方式继承复用父类骨架组合通过持有策略对象复用变化粒度算法内部某几步变化整个算法族可替换扩展方式继承子类覆写步骤新写策略类替换上下文中的策略与业务结合适合“骨架稳定步骤多变”的场景适合“整个算法可替换”的场景风险点继承层级深后不好维护策略类数量多后需要管理个人看法模板方法模式的耦合度比策略模式高因为子类依赖父类所以一旦骨架发生变化所有子类都要跟着检查。策略模式通过组合耦合度低一些但代价是增加了一批策略类和上下文之间的交互代码。实际项目中我经常两个搭配着用用策略模式定义大的算法边界用模板方法模式处理策略内部的可变步骤。比如支付策略的接口用策略模式定义但每个支付策略内部都有固定流程那就再抽一个模板基类。4. 观察者模式让状态变化自己“广播”出去4.1 气象站的经典结构观察者模式应该是最容易理解的行为型模式了。它的核心思想就一句话当一个对象的状态发生变化时所有依赖它的对象都会自动收到通知。一对多的依赖关系这边状态一变那边所有观察者都被触发。经典的教学案例是气象站WeatherData负责采集气象数据数据一变DisplayBoard显示面板、AlertSystem预警系统等多个观察者都要更新。用代码写出来是这样一个结构// 观察者接口 public interface WeatherObserver { void update(float temperature, float humidity, float pressure); } // 被观察者主题 public class WeatherData { private ListWeatherObserver observers new ArrayList(); private float temperature; private float humidity; private float pressure; public void register(WeatherObserver o) { observers.add(o); } public void unregister(WeatherObserver o) { observers.remove(o); } public void setMeasurements(float temperature, float humidity, float pressure) { this.temperature temperature; this.humidity humidity; this.pressure pressure; notifyObservers(); } private void notifyObservers() { for (WeatherObserver observer : observers) { observer.update(temperature, humidity, pressure); } } }观察者那边实现接口即可public class AlertSystem implements WeatherObserver { Override public void update(float temperature, float humidity, float pressure) { if (temperature 35f) { System.out.println(高温预警); } } }4.2 我踩过好几次的监听器生命周期问题观察者模式在真实项目中有一个非常隐蔽的坑观察者注册了之后没有及时注销造成内存泄漏。举个例子某后台管理系统里用户登录后需要实时接收系统通知。很多人会在用户对象创建时把UserSessionListener注册到全局NotificationCenter上但用户退出登录时忘了调用unregister。结果就是这个监听器一直被全局对象持有用户明明已经退出了GC还是无法回收它关联的一堆对象。在长期运行的服务器上这就是个定时炸弹内存悄悄涨直到某天OOM。我的经验是两条铁律谁注册谁负责注销。注册和注销必须成对出现最好写在同一个方法里比如start()和destroy()。如果无法保证成对出现使用弱引用。Java里可以用WeakReference来包装观察者或者直接用现成的WeakHashMap做监听器存储。4.3 观察者模式在实战中的变体实际开发中很少真的手写一整套观察者接口。大多数时候我们会用事件总线、异步消息、发布订阅框架。Java自身的PropertyChangeSupport、各种消息中间件的Consumer/Producer模型本质上都是观察者模式的扩展。但不管用什么工具核心的语义没变发布者不关心谁在听订阅者不关心谁在发声双方只靠事件类型和内容进行松耦合对接。这带来一个隐蔽的调试难度事件一多代码的调用链就变得很“飘”。你看到一个现象发生了但不知道是哪个发布者触发、经过了几层异步转发。我的建议是观察者模式适合跨模块的、低频次的、一对多的通知。如果模块内部逻辑强相关高频调用硬套观察者模式会让代码变得特别难追踪这时候不如直接方法调用。另外有一个实战细节通知顺序。默认的ArrayList是按注册顺序遍历的这本身没问题。但如果你在某个观察者的update里又触发了一个新事件就可能出现迭代器修改冲突ConcurrentModificationException或者通知顺序错乱。稳妥做法是遍历之前对观察者列表做一份快照或者让通知操作脱离当前线程去执行。5. 迭代器模式把“怎么遍历”从集合里拆出来5.1 为什么需要迭代器模式迭代器模式可能是行为型模式里最“没存在感”的一个因为现代语言几乎都内置了迭代器语法比如Java的Iterator接口、foreach语法糖、Python的__iter__和__next__。很多人以为这个模式已经过时了其实不然。迭代器模式的核心价值不是“怎么遍历一个数组”而是把遍历逻辑和集合内部结构解耦。调用方不需要知道集合底层是数组、链表还是树只需要调用hasNext()和next()就能依次拿到元素。当一个集合的数据结构足够简单时确实用不上迭代器——直接用下标遍历就行。但真实项目里集合往往不是铁板一块有的集合存储的是多级树形结构遍历时要按层级返回有的集合内部有多个分组调用方需要按不同规则遍历有的集合在遍历过程中还要做过滤和转换这时候把遍历算法内聚成一个迭代器对象价值就体现出来了。5.2 手写一个可迭代的订单历史举个实际例子。某订单中心需要按时间倒序遍历用户的历史订单同时只返回已支付订单。我定义了一个OrderHistory集合类内部用List存储但对外暴露一个定制迭代器public class OrderHistory implements IterableOrderInfo { private ListOrderInfo orders new ArrayList(); public void add(OrderInfo order) { orders.add(order); } Override public IteratorOrderInfo iterator() { return new PaidOrderIterator(); } // 迭代器按时间倒序并过滤未支付 private class PaidOrderIterator implements IteratorOrderInfo { private int cursor orders.size() - 1; private OrderInfo nextReady; Override public boolean hasNext() { while (cursor 0) { OrderInfo candidate orders.get(cursor); if (candidate.isPaid()) { nextReady candidate; cursor--; return true; } cursor--; } return false; } Override public OrderInfo next() { if (nextReady null !hasNext()) { throw new NoSuchElementException(); } OrderInfo result nextReady; nextReady null; return result; } } }调用方不需要知道OrderHistory内部用了ArrayList、需要倒序访问、还要过滤状态。直接foreach循环for (OrderInfo order : orderHistory) { System.out.println(order.getOrderId()); }这个把复杂遍历逻辑封装进迭代器的做法让调用代码非常干净。5.3 迭代器陷阱迭代器最经典的坑是快速失败fail-fast与并发修改。Java里如果在迭代过程中有其他线程修改了集合结构ArrayList会抛出ConcurrentModificationException。这是保护机制但很多人第一次遇到时都会懵。我的建议是单线程环境下尽量在迭代过程中不要修改集合结构确实需要改的用CopyOnWriteArrayList或ConcurrentHashMap这类并发容器。还有一种做法是先把需要删除的元素收集起来迭代结束后统一删除。另外一个容易被忽略的点迭代器是“一次性”的不能回溯。如果你在一个场景里需要多次遍历同一个集合每次都调用iterator()获取新迭代器而不是复用同一个迭代器对象。6. 责任链模式请求自己找“能处理它的人”6.1 从报销审批看责任链责任链模式的思路非常贴近现实。拿报销审批来说报销金额不同需要不同级别的人审批500元以下项目经理批5000元以下部门总监批50000元以下总经理批超过50000董事会批最直觉的写法是if/else嵌套public void approve(ReimbursementRequest request) { if (request.getAmount() 500) { manager.approve(request); } else if (request.getAmount() 5000) { director.approve(request); } else if (...) { ... } }问题很明显审批规则一变就要改这个方法而且随着规则变复杂这个类会长得没法看。责任链模式的做法是把每个审批节点拆成独立的处理器串成一条链请求从链头进入能处理的节点处理掉处理不了就往后传。6.2 责任链的代码结构public abstract class ApprovalHandler { protected ApprovalHandler next; public void setNext(ApprovalHandler next) { this.next next; } public void handle(ReimbursementRequest request) { if (canApprove(request)) { doApprove(request); } else if (next ! null) { next.handle(request); } else { request.setApproved(false); System.out.println(无人能审批直接驳回); } } protected abstract boolean canApprove(ReimbursementRequest request); protected abstract void doApprove(ReimbursementRequest request); }具体节点实现public class ManagerHandler extends ApprovalHandler { Override protected boolean canApprove(ReimbursementRequest request) { return request.getAmount() 500; } Override protected void doApprove(ReimbursementRequest request) { System.out.println(项目经理审批通过金额: request.getAmount()); } } public class DirectorHandler extends ApprovalHandler { Override protected boolean canApprove(ReimbursementRequest request) { return request.getAmount() 500 request.getAmount() 5000; } Override protected void doApprove(ReimbursementRequest request) { System.out.println(总监审批通过金额: request.getAmount()); } }客户端把链组装起来ApprovalHandler manager new ManagerHandler(); ApprovalHandler director new DirectorHandler(); ApprovalHandler gm new GeneralManagerHandler(); manager.setNext(director); director.setNext(gm); manager.handle(request);这套写法的好处非常直接新增审批节点只需新写一个Handler类然后在组装链的地方拼接一下完全不用动已有节点的代码。6.3 责任链的边界什么时候该停责任链模式用多了之后有一个问题值得警惕请求在链上传递时如果没有任何节点能处理就会走到链尾表现就是“石沉大海”或者被默认逻辑兜底。我在一个日志框架项目里就遇到过这种情况。当时设计了一组日志过滤器按“DEBUG → INFO → WARN → ERROR”的顺序传递。结果有一次配置错误某个级别的过滤器没有注册到链上大量日志直接穿过链尾既没输出也没处理排查了半天才找到问题。从那以后我给自己定了几条规矩责任链必须有明确的链尾兜底逻辑。要么在handle的最后写清楚“无人处理时怎么办”要么在组装链时保证最后一个节点一定能处理。责任链不能太长。超过五六个节点调试和阅读成本会显著上升。如果业务本身没有天然的“传递”语义不要硬套责任链。节点顺序很重要。责任链上的顺序有时候就是业务规则的一部分组装链的地方应该集中配置并且要写注释说明为什么是这个顺序。7. 五种模式放在一起怎么选写到这里我们把五个模式都过了一遍。最后用一个表格横向对比一下再聊聊团队协作时怎么选型。模式核心思想适用场景主要风险策略模式算法族封装可整体替换支付渠道、优惠规则、排序算法策略类爆炸工厂膨胀模板方法模式骨架固定步骤留给子类订单处理流程、数据迁移流程继承层级深骨架改动影响大观察者模式一对多状态通知事件广播、消息推送、UI刷新监听器泄漏调用链难追踪迭代器模式遍历逻辑与结构解耦自定义集合遍历、过滤排序遍历并发修改异常迭代器复用出错责任链模式请求沿链传递直到有人处理审批流、日志过滤器、拦截器链尾无兜底顺序错误难发现选型时我的判断顺序一般是这样的先看变化发生的位置。如果是“整个算法都能换”选策略模式如果是“算法骨架稳定只有某几步会变”选模板方法模式如果变化的是“对象状态变化后谁要跟着动”选观察者模式。再看调用关系。如果多个对象之间的交互是一对多的广播观察者模式最顺手如果请求和处理器之间是传递关系责任链模式更贴切如果只是想让外部顺序访问内部元素迭代器模式就够了。最后看团队熟悉程度。设计模式的引入不是炫技要考虑队友后续的维护成本。一个团队如果用策略模式和模板方法用得顺手那就优先用这两种解决大部分问题观察者模式要慎用因为它会切断调用方和被调用方之间的直接联系新人接手代码时经常找不到逻辑在哪。责任链模式适合业务本身有“层级审批”语义的场景没事别硬造链。我自己在项目里的习惯是策略、模板方法、迭代器这三种模式几乎每天都会用观察者和责任链则要结合具体业务场景判断绝不为了用模式而用模式。这篇先讲到这里。行为型模式还有六个——状态、命令、备忘录、访问者、中介者、解释器其中状态模式和命令模式在真实项目里出现频率非常高等下一篇接着聊。最后分享一个小技巧学设计模式别只看结构试着在脑子里把每个模式对应到一个你写过的真实代码场景。能对上号说明你真正理解了。

相关新闻

K均值聚类实战:从原理到落地的完整指南

K均值聚类实战:从原理到落地的完整指南

1. 从一个真实需求说起:为什么聚类值得花时间搞明白做数据这行的朋友大概率都遇到过这种场景:手里攥着一份几万行的用户行为表,老板说“把这些人分分类,看看有没有什么规律”,但表里压根没有现成的标签,也没…

2026/10/13 12:24:19 阅读更多 →
图像形成物理:计算机视觉的底层逻辑与工程避坑指南

图像形成物理:计算机视觉的底层逻辑与工程避坑指南

我最早翻到《图像处理、分析与机器视觉(第四版)》的"图像形成物理"这一章时,第一反应是直接跳过。直觉告诉我,前面几章才是重头戏,图像形成不过是点物理常识,无非就是"光打到物体上、镜头收…

2026/10/13 12:24:19 阅读更多 →
AI基础经典试题全解析:归结反演与α-β剪枝手推题攻略

AI基础经典试题全解析:归结反演与α-β剪枝手推题攻略

简介:百度人工智能岗位的经典考试试题文档,覆盖语义网络、知识表示、推理方式、机器学习及自然语言处理等核心模块,并配有完整答案解析。题目按选择题、填空题、简答计算题、应用题四种形式编排,适合正在准备百度或同类互联网公司…

2026/10/13 12:24:19 阅读更多 →

最新新闻

S12芯片ATD模拟量采集与12864显示实践全解析

S12芯片ATD模拟量采集与12864显示实践全解析

简介:一份基于飞思卡尔 MC9S12DG128 的 AD 采集与显示实验资源,适合嵌入式初学者、单片机课程设计或 S12 系列开发者参考。资源演示了如何利用芯片内置的多通道 8 位高速 AD 转换器进行数据采集,并通过 12864 液晶屏实时显示结果,…

2026/10/13 13:04:16 阅读更多 →
STM32蓝牙电机控制方案:从硬件接线到断连保护全解析

STM32蓝牙电机控制方案:从硬件接线到断连保护全解析

简介:基于STM32微控制器的蓝牙与电机控制工程,面向嵌入式学习者、物联网开发者和毕设学生,解决通过低功耗蓝牙远程遥控电机的软硬件一体实现问题。工程以Keil项目形式组织,内含STM32标准外设库的USART、定时器、PWM、GPIO等驱动配…

2026/10/13 13:04:16 阅读更多 →
SAP HANA Studio安装包选型与连接配置避坑指南

SAP HANA Studio安装包选型与连接配置避坑指南

简介:SAP HANA Studio 安装包面向 SAP HANA 平台开发者、数据建模人员及企业 IT 运维人员,用于设计、开发和管理基于 HANA 的应用程序与服务,帮助读者在本地搭建完整的 IDE 环境,连接 HANA 实例开展数据建模、数据库管理与应用调试…

2026/10/13 13:04:16 阅读更多 →
Linux开发板Qt实现《欢乐颂》:音频合成与交叉编译全攻略

Linux开发板Qt实现《欢乐颂》:音频合成与交叉编译全攻略

简介:这是一份面向嵌入式Linux初学者的Qt应用开发实例,基于S3C6410开发板实现“欢乐颂”音乐播放与跑马灯控制。资源定位清晰,涵盖Qt GUI编程、GPIO操作、蜂鸣器驱动及按键事件监听等关键知识点,适合正在学习Linux开发板应用开发或…

2026/10/13 13:04:16 阅读更多 →
模拟退火算法入门实战:Python求解八皇后问题

模拟退火算法入门实战:Python求解八皇后问题

先说结论:八皇后问题是我见过最适合讲模拟退火算法的入门案例。问题本身的规则简单到一句话就能说清——8个皇后放在8乘8棋盘上,任意两个不能互相攻击。但真靠手工慢慢摆,普通人大概率要折腾一下午;而用模拟退火算法配一份Python源…

2026/10/13 13:04:16 阅读更多 →
游戏框架UI模块设计:生命周期、层级管理与对象池实践

游戏框架UI模块设计:生命周期、层级管理与对象池实践

1. 从零拆解一个游戏框架的UI模块:我踩过的坑和最终沉淀的方案 做游戏开发这些年,前前后后接触过不少自研框架和商业引擎的UI方案。早期项目里,UI代码和业务逻辑搅在一起,改一个按钮的响应逻辑要翻三四个文件,那种酸爽…

2026/10/13 13:03:14 阅读更多 →

日新闻

物联网系统集成避坑指南:从选型到验收的关键要点

物联网系统集成避坑指南:从选型到验收的关键要点

做了这么多年物联网系统集成的项目,我最大的感受是,大部分坑不是出在技术前沿,而是出在一些看起来很平常的地方。设备选了便宜的、协议没问清楚、现场没摸透、验收标准写得含糊——这些细枝末节,最后都会变成延期、超支和扯皮的大…

2026/10/13 0:00:57 阅读更多 →
ESP32舵机控制全攻略:从PWM原理到高级玩法与常见故障排查

ESP32舵机控制全攻略:从PWM原理到高级玩法与常见故障排查

如果你玩ESP32有一阵子了,很难不碰到舵机控制这道坎。做智能小车要转方向,做机械臂要抬关节,做云台要偏航俯仰,背后都是同一个东西在干活:舵机。而我见过太多人卡在“代码能编译、舵机就是不听话”这个阶段&#xff0c…

2026/10/13 0:00:57 阅读更多 →
CAN总线原理与STM32实战:抗干扰、仲裁、错误处理全解析

CAN总线原理与STM32实战:抗干扰、仲裁、错误处理全解析

1. 为什么CAN总线至今仍是工业现场的“硬通货”?——从汽车底盘到智能温室的真实需求你有没有拆过一辆老款燃油车的中控台?或者调试过某高校实验室里那台跑着Modbus协议却频频丢帧的PLC控制柜?又或者,在某个农业物联网项目里&…

2026/10/13 0:00:57 阅读更多 →

周新闻

流感时间序列预测实战:ARIMA/LSTM全流程拆解与避坑指南

流感时间序列预测实战:ARIMA/LSTM全流程拆解与避坑指南

简介:基于 ARIMA、LSTM、Transformer 等模型的流感时间序列预测 Python 源码,面向计算机相关专业课程设计与期末大作业学生,以及项目实战学习者。内容覆盖预处理、平稳性检验、定阶、残差分析、多模型对比预测的完整时序建模流程,…

2026/10/13 2:54:56 阅读更多 →
影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别

影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别

影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别 做影刀RPA自动化,十个新手有八个栽在"往输入框里填东西"这件事上:要么填不进去,要么填了一半,要么直接把原来内容追加在后面。这背后的根因&…

2026/10/12 0:16:38 阅读更多 →
影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容

影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容

影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容 1. 认识影刀:什么场景该用RPA采小说数据 起点中文网的页面结构相对稳定——分类榜单、书籍详情、章节内容三块独立页面,跳转链路清晰。这种场景非常适合影刀自动化&#x…

2026/10/13 1:58:08 阅读更多 →

月新闻

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

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

2026/10/12 21:05:09 阅读更多 →
Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

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

2026/10/12 14:48:49 阅读更多 →
黑夜航拍船只数据集训练YOLOV5模型全流程解析

黑夜航拍船只数据集训练YOLOV5模型全流程解析

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

2026/10/12 18:11:17 阅读更多 →