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

Java 设计模式——原则:从理论约束到项目落地指南

Java 设计模式——原则:从理论约束到项目落地指南

设计模式的原则不是 “教条式的规则”,而是 “写出可维护、可扩展代码的底层逻辑”—— 就像盖房子要先打地基,遵循这些原则,才能让你的代码在需求迭代中不变成 “祖传代码”。本文不仅拆解 6 大原则的核心定义,更会结合Java 实战场景设计模式关联,让你知道 “每个原则在项目中如何用、对应哪些模式的设计逻辑”。

文章目录

  • Java 设计模式——原则:从理论约束到项目落地指南
    • 一、核心认知:为何设计原则如此重要?
    • 二、6 大设计原则深度解析(附实战场景 + 模式关联)
      • 1. 单一职责原则:一个类 / 方法只做一件事(基础原则)
        • 核心定义
        • 为什么要遵守?
        • 实战案例:从 “臃肿 Controller” 到 “职责拆分”
        • 落地注意点
      • 2. 开闭原则:对扩展开放,对修改关闭(核心原则)
        • 核心定义
        • 为什么要遵守?
        • 实战案例:支付方式扩展(结合 SpringBoot 依赖注入)
        • 落地关键手段
      • 3. 里氏替换原则:子类可替换父类,且不改变程序行为(实现开闭的基础)
        • 核心定义
        • 为什么要遵守?
        • 实战案例:用户类型扩展(重置密码功能)
        • 子类约束规则
      • 4. 依赖倒转原则:针对抽象编程,而非具体实现(架构级原则)
        • 核心定义
        • 为什么要遵守?
        • 实战案例:数据访问层扩展(Service 依赖 DAO 接口)
        • 落地关键:依赖注入(DI)
      • 5. 接口隔离原则:用多个专用接口,替代一个万能接口(接口设计原则)
        • 核心定义
        • 为什么要遵守?
        • 实战案例:动物行为接口拆分
        • 落地注意点
      • 6. 合成复用原则:优先用对象组合,而非继承(复用方式原则)
        • 核心定义
        • 为什么要遵守?
        • 实战案例:通知功能的复用方式对比
        • 继承与组合的选择标准
    • 三、6 大原则的关联逻辑与实战优先级
      • 1. 原则间的核心关联
      • 2. 实战优先级(按落地顺序)
      • 3. 常见误区:过度遵循原则
    • 四、总结:设计原则的本质是 “平衡”

一、核心认知:为何设计原则如此重要?

面向对象设计的核心矛盾是 “需求多变” 与 “代码难改” 的冲突。设计原则正是解决这一矛盾的 “底层方法论”:

  • 它是设计模式的 “评判标准”:比如 “策略模式符合开闭原则”“继承过度违反合成复用原则”,懂原则才能懂模式的设计初衷;

  • 它是日常编码的 “避坑指南”:哪怕不用设计模式,遵循原则也能让你的 Controller、Service 代码更简洁、低耦合;

  • 它是架构设计的 “基础逻辑”:SpringBoot、MyBatis 等框架的源码,本质上都是设计原则的极致体现(如 Spring 的依赖注入对应依赖倒转原则)。

二、6 大设计原则深度解析(附实战场景 + 模式关联)

1. 单一职责原则:一个类 / 方法只做一件事(基础原则)

核心定义

一个类只负责一个功能领域的职责,仅存在一个引起它变化的原因

为什么要遵守?
  • 降低耦合:一个类只做一件事,修改时不会影响其他功能(如支付类改逻辑,不会影响登录功能);

  • 提高复用:职责单一的类 / 方法,更容易被其他模块复用(如单独的 “密码加密工具类”,可在登录、注册、修改密码场景复用);

  • 简化维护:代码逻辑聚焦,出问题时能快速定位(如支付失败,只需要查支付相关类,不用看登录代码)。

实战案例:从 “臃肿 Controller” 到 “职责拆分”

反例:租车平台的UserController包含登录、注册、押金支付、套餐支付等所有功能(如原文代码),问题是 “改支付逻辑要动 UserController,可能影响登录功能”。

正例:按职责拆分,配合包结构分层,让每个类聚焦单一功能:

com.rental.user          // 用户模块根包├─ controller│  ├─ LoginController.java  // 仅负责登录逻辑│  ├─ RegisterController.java  // 仅负责注册逻辑│  └─ PayController.java     // 仅负责支付相关逻辑├─ service│  ├─ LoginService.java      // 登录业务逻辑│  ├─ RegisterService.java   // 注册业务逻辑│  └─ PayService.java        // 支付业务逻辑└─ model└─ User.java              // 仅定义用户数据结构

关联设计模式:所有模式的基础(如工厂方法模式的 “工厂类只创建对应产品”、策略模式的 “策略类只实现一种算法”)。

落地注意点
  • 粒度把控:不用过度拆分(如把 “用户姓名校验” 拆成单独类),以 “业务功能” 为单位(如 “登录”“支付” 是独立业务);

  • 方法级也适用:一个方法只做一件事(如login()只负责登录流程,密码加密单独抽成encryptPassword()方法)。

2. 开闭原则:对扩展开放,对修改关闭(核心原则)

核心定义

软件实体(类、模块、方法)应尽量通过扩展实现需求变化,而非修改原有代码

这是设计模式的 “终极目标”—— 所有其他原则和模式,最终都是为了满足开闭原则。

为什么要遵守?
  • 降低风险:修改原有代码可能引入未知 bug(如改支付逻辑导致登录失败),扩展则只新增代码,不影响旧功能;

  • 减少测试成本:原有功能无需重新测试,只需测试新增的扩展代码;

  • 提高迭代效率:需求变化时,直接新增类 / 方法即可,不用通读旧代码找修改点。

实战案例:支付方式扩展(结合 SpringBoot 依赖注入)

反例:支付类用if-else判断支付类型,新增 “银联支付” 需修改pay()方法(如原文代码):

// 反例:违反开闭原则
public class DepositPay {public void pay(String type) {if (type.equals("ali")) { new AliPay().pay(); } else if (type.equals("wx")) { new WXPay().pay(); }// 新增银联支付,需加else if,修改原有代码}
}

正例:通过 “接口 + 实现类 + 依赖注入” 扩展,新增支付方式无需改旧代码:

// 1. 定义支付接口(抽象层,稳定不修改)
public interface Pay {void pay();
}// 2. 实现具体支付类(扩展层,新增支付方式只需加类)
@Service("aliPay")
public class AliPay implements Pay {@Overridepublic void pay() { System.out.println("支付宝支付"); }
}@Service("wxPay")
public class WXPay implements Pay {@Overridepublic void pay() { System.out.println("微信支付"); }
}// 新增银联支付:只需加类,不用改旧代码
@Service("ylPay")
public class YlPay implements Pay {@Overridepublic void pay() { System.out.println("银联支付"); }
}// 3. 支付服务(依赖抽象,不依赖具体实现)
@Service
public class DepositPayService {// Spring自动注入所有Pay实现类到map(key=beanName,value=实现类)@Autowiredprivate Map<String, Pay> payMap;// 按支付类型获取对应实现,无需修改public void pay(String payType) {Pay pay = payMap.get(payType);if (pay == null) { throw new RuntimeException("支付方式不存在"); }pay.pay();}
}

关联设计模式:策略模式(扩展策略)、工厂方法模式(扩展产品)、观察者模式(扩展观察者)等几乎所有模式。

落地关键手段
  • 抽象约束:用接口 / 抽象类定义稳定的抽象层,具体实现通过子类扩展;

  • 依赖注入:通过 Spring 的 DI、配置文件等方式,动态加载扩展类(如上述案例的payMap自动注入);

  • 封装变化:将可能变化的逻辑(如支付方式、优惠规则)封装成独立模块,扩展时只改该模块。

3. 里氏替换原则:子类可替换父类,且不改变程序行为(实现开闭的基础)

核心定义

所有引用父类(或接口)的地方,都可以无感知地替换为其子类对象,程序行为不变

简单说:“子类是父类的有效扩展,而非破坏父类逻辑”(如 “狗是动物”,但 “动物不一定是狗”,用狗替换动物没问题,用动物替换狗则可能有问题)。

为什么要遵守?
  • 保证抽象的有效性:如果子类不能替换父类,那么 “针对抽象编程”(依赖倒转原则)就无法实现;

  • 避免子类破坏父类逻辑:如父类规定 “订单金额不能为负”,子类却允许负金额,会导致调用父类的地方出 bug。

实战案例:用户类型扩展(重置密码功能)

反例:VIP 用户重置密码逻辑破坏父类规则(如父类要求 “密码长度≥6”,子类却允许 3 位密码):

// 父类:普通用户
public class Customer {public void resetPassword(String password) {if (password.length() < 6) { throw new RuntimeException("密码太短"); }}
}// 子类:VIP用户,破坏父类规则
public class VIPCustomer extends Customer {@Overridepublic void resetPassword(String password) {// 允许3位密码,替换父类后会导致依赖父类的地方出bugif (password.length() < 3) { throw new RuntimeException("密码太短"); }}
}

正例:子类遵循父类约束,只扩展额外功能(如 VIP 用户重置后发送短信通知):

// 父类:抽象用户(更符合里氏替换,避免具体类继承)
public abstract class AbstractCustomer {// 父类定义核心约束,子类不能破坏public final void resetPassword(String password) {if (password.length() < 6) { throw new RuntimeException("密码太短"); }doResetPassword(password); // 子类实现具体逻辑}// 子类扩展的抽象方法protected abstract void doResetPassword(String password);
}// 普通用户子类
public class CommonCustomer extends AbstractCustomer {@Overrideprotected void doResetPassword(String password) {System.out.println("普通用户重置密码:" + password);}
}// VIP用户子类:扩展通知功能,不破坏父类约束
public class VIPCustomer extends AbstractCustomer {@Overrideprotected void doResetPassword(String password) {System.out.println("VIP用户重置密码:" + password);sendSmsNotice(); // 新增VIP专属通知}private void sendSmsNotice() {System.out.println("发送VIP密码重置通知");}
}// 调用处:针对父类编程,子类可无感知替换
public class ResetPasswordService {public void reset(AbstractCustomer customer, String password) {customer.resetPassword(password); // 用Common或VIP替换,行为都符合父类约束}
}

关联设计模式:依赖倒转原则的基础(没有里氏替换,依赖抽象就会出问题)、工厂方法模式(子类工厂创建子类产品,替换父类工厂没问题)。

子类约束规则
  1. 不重写父类的非抽象方法(如父类已实现的resetPassword(),子类不要重写,可通过抽象方法扩展);

  2. 子类方法的前置条件(参数)比父类更宽松(如父类参数是 “String 密码”,子类可以是 “Object 密码”,但反之不行);

  3. 子类方法的后置条件(返回值)比父类更严格(如父类返回 “List”,子类可以返回 “ArrayList”,但反之不行)。

4. 依赖倒转原则:针对抽象编程,而非具体实现(架构级原则)

核心定义

抽象不依赖于细节,细节依赖于抽象,可拆解为两层含义:

  1. 高层模块(如 Service)不依赖低层模块(如 DAO),二者都依赖抽象(如 DAO 接口);

  2. 抽象(接口 / 抽象类)不依赖具体实现(子类),具体实现依赖抽象。

这是 Spring 框架的核心设计思想(如依赖注入、控制反转)。

为什么要遵守?
  • 解耦高层与低层:如 Service 不用关心 DAO 是用 MySQL 还是 PostgreSQL,只需依赖 DAO 接口,切换数据库只需换 DAO 实现;

  • 提高扩展性:新增低层实现(如新增 MongoDB DAO),高层模块无需修改。

实战案例:数据访问层扩展(Service 依赖 DAO 接口)

反例:Service 直接依赖具体 DAO 实现(MySQL),切换 PostgreSQL 需改 Service 代码:

// 低层模块:MySQL DAO
public class UserMysqlDao {public User getById(Long id) { /* MySQL查询 */ }
}// 高层模块:Service依赖具体DAO,耦合过高
@Service
public class UserService {// 直接依赖MySQL DAO,切换数据库需改这里private UserMysqlDao userDao = new UserMysqlDao();public User getUser(Long id) {return userDao.getById(id);}
}

正例:Service 依赖 DAO 接口,低层实现通过 Spring 注入,切换数据库只需换实现类:

// 1. 抽象DAO接口(高层和低层都依赖)
public interface UserDao {User getById(Long id);
}// 2. 低层实现:MySQL DAO
@Repository("mysqlUserDao")
public class UserMysqlDao implements UserDao {@Overridepublic User getById(Long id) { System.out.println("MySQL查询用户"); return new User(); }
}// 3. 低层实现:PostgreSQL DAO(扩展,不用改高层)
@Repository("pgUserDao")
public class UserPgDao implements UserDao {@Overridepublic User getById(Long id) { System.out.println("PostgreSQL查询用户"); return new User(); }
}// 4. 高层Service:依赖抽象,不依赖具体实现
@Service
public class UserService {// 注入接口,通过配置文件切换实现(如application.yml中配置userDao: mysqlUserDao)@Autowired@Qualifier("${userDao}")private UserDao userDao;public User getUser(Long id) {return userDao.getById(id); // 不用关心是MySQL还是PostgreSQL}
}

关联设计模式:所有基于抽象的模式(工厂方法、抽象工厂、策略、代理等),是这些模式的核心支撑。

落地关键:依赖注入(DI)

通过 3 种方式将具体实现注入到依赖抽象的地方:

  1. 构造注入:通过构造函数传入(如public UserService(UserDao userDao) {});

  2. Setter 注入:通过 set 方法传入(如public void setUserDao(UserDao userDao) {});

  3. 接口注入:通过实现特定接口传入(Spring 中较少用,构造 / Setter 更常用)。

5. 接口隔离原则:用多个专用接口,替代一个万能接口(接口设计原则)

核心定义

客户端不应该依赖它不需要的接口,即 “一个接口只对应一个角色,不包含无关方法”(如 “人” 不需要 “飞” 的接口,“鸟” 不需要 “工作” 的接口)。

为什么要遵守?
  • 避免接口臃肿:一个包含 10 个方法的 “万能接口”,客户端可能只需要 2 个,却要实现所有 10 个方法(哪怕是空实现);

  • 降低耦合:接口拆分后,客户端只依赖自己需要的接口,修改一个接口不会影响其他客户端。

实战案例:动物行为接口拆分

反例:万能接口IAnimal包含 “吃、工作、飞”,导致 “人” 必须实现 “飞”(空实现或抛出异常):

// 反例:万能接口,包含无关方法public interface IAnimal {void eat();   // 所有人/动物都需要void work();  // 只有人需要void fly();   // 只有鸟需要}// 人实现接口,必须实现不需要的fly()public class Tony implements IAnimal {@Override public void eat() {}@Override public void work() {}@Override public void fly() { throw new RuntimeException("不会飞"); } // 冗余}

正例:按角色拆分接口,客户端只依赖需要的接口:

// 1. 基础行为接口(所有动物都需要)
public interface BasicAnimalBehavior {void eat();void sleep();}// 2. 人类特有行为接口
public interface HumanBehavior {void work();void playCard();}// 3. 鸟类特有行为接口
public interface BirdBehavior {void fly();}// 人:只依赖基础行为+人类行为接口
public class Tony implements BasicAnimalBehavior, HumanBehavior {@Override public void eat() { System.out.println("人吃饭"); }@Override public void sleep() { System.out.println("人睡觉"); }@Override public void work() { System.out.println("人工作"); }@Override public void playCard() { System.out.println("人打牌"); }}// 鸟:只依赖基础行为+鸟类行为接口
public class Bird implements BasicAnimalBehavior, BirdBehavior {@Override public void eat() { System.out.println("鸟吃饭"); }@Override public void sleep() { System.out.println("鸟睡觉"); }@Override public void fly() { System.out.println("鸟飞"); }}

关联设计模式:适配器模式(适配专用接口)、组合模式(子组件只依赖所需接口)。

落地注意点
  • 避免接口过度拆分:如把 “吃” 拆成 “吃米饭”“吃面条” 接口,会导致接口泛滥;

  • 按 “客户端需求” 拆分:接口的粒度以 “客户端需要的最小功能集” 为单位(如 “支付接口” 包含 “发起支付”“查询结果”,这是客户端需要的最小集,不用拆分);

  • 结合业务角色:如 “管理员” 和 “普通用户” 是不同角色,应分别定义AdminBehaviorUserBehavior接口,而非用一个UserBehavior包含所有权限方法。

6. 合成复用原则:优先用对象组合,而非继承(复用方式原则)

核心定义

尽量通过对象组合(Has-A)或聚合(Contains-A)实现代码复用,而非依赖类继承(Is-A)

继承是 “强耦合” 关系(子类依赖父类实现),组合是 “弱耦合” 关系(通过调用对象方法复用,不依赖实现细节)。

为什么要遵守?
  • 降低耦合:父类修改时,子类可能被迫修改(如父类删除一个方法,所有子类都会报错);组合则只需保证被组合对象的接口不变,实现修改不影响使用者;

  • 提高灵活性:组合可动态切换被组合对象(如支付服务可动态切换 “短信通知” 或 “邮件通知”),继承则在编译时就固定了父类;

  • 避免继承滥用:过度继承会形成 “类爆炸”(如UserCommonUserCommonVipUserCommonVipAnnualUser),组合则更简洁。

实战案例:通知功能的复用方式对比

反例:用继承实现通知功能,新增 “邮件通知” 需新增子类,且无法动态切换:

// 父类:短信通知
public class SmsNotice {public void sendNotice(String content) {System.out.println("短信通知:" + content);}
}// 子类:订单支付通知(继承短信通知)
public class OrderPayNotice extends SmsNotice {public void notifyUser(Long orderId) {String content = "订单" + orderId + "支付成功";super.sendNotice(content); // 依赖父类实现}
}// 问题:新增邮件通知,需新增继承EmailNotice的子类,且无法在订单通知中动态切换短信/邮件
public class EmailNotice {public void sendNotice(String content) {System.out.println("邮件通知:" + content);}
}public class OrderPayEmailNotice extends EmailNotice {// 重复订单通知逻辑,仅通知方式不同public void notifyUser(Long orderId) {String content = "订单" + orderId + "支付成功";super.sendNotice(content);}
}

正例:用组合实现通知功能,新增通知方式无需改旧代码,可动态切换:

// 1. 定义通知接口(抽象层,稳定)
public interface Notice {void sendNotice(String content);
}// 2. 实现具体通知类(可扩展)
public class SmsNotice implements Notice {@Overridepublic void sendNotice(String content) {System.out.println("短信通知:" + content);}
}public class EmailNotice implements Notice {@Overridepublic void sendNotice(String content) {System.out.println("邮件通知:" + content);}
}// 3. 订单通知服务:组合Notice接口,而非继承
public class OrderPayNotice {// 组合Notice对象,可通过构造/Setter注入,动态切换private Notice notice;// 构造注入,灵活传入不同通知方式public OrderPayNotice(Notice notice) {this.notice = notice;}public void notifyUser(Long orderId) {String content = "订单" + orderId + "支付成功";notice.sendNotice(content); // 依赖接口,不依赖实现}// Setter方法,支持运行时切换通知方式public void setNotice(Notice notice) {this.notice = notice;}
}// 调用处:动态切换通知方式
public class NoticeTest {public static void main(String[] args) {// 短信通知OrderPayNotice smsNotice = new OrderPayNotice(new SmsNotice());smsNotice.notifyUser(123L);// 动态切换为邮件通知smsNotice.setNotice(new EmailNotice());smsNotice.notifyUser(456L);}
}

关联设计模式:桥接模式(抽象与实现通过组合分离)、装饰模式(通过组合动态增强对象功能)、策略模式(通过组合切换策略算法)。

继承与组合的选择标准
场景优先选择原因
子类与父类是 “is-a” 关系(如 “狗是动物”)继承逻辑上符合继承语义,且父类稳定(如Dog extends Animal
子类与父类是 “has-a” 关系(如 “订单有通知”)组合逻辑上是包含关系,需灵活切换实现(如订单包含 “短信通知” 或 “邮件通知”)
父类频繁修改组合避免子类跟随父类修改,降低耦合
需要动态切换功能组合继承无法在运行时切换父类,组合可动态替换被组合对象

三、6 大原则的关联逻辑与实战优先级

设计原则不是孤立的,而是相互支撑、共同服务于 “可维护、可扩展” 的目标,掌握它们的关联关系,才能在项目中灵活运用:

1. 原则间的核心关联

  • 基础层:单一职责原则是所有原则的基础 —— 只有先拆分职责,才能谈接口隔离(拆分接口)、合成复用(组合单一职责的对象);

  • 目标层:开闭原则是最终目标 —— 里氏替换(保证子类可扩展)、依赖倒转(依赖抽象)、接口隔离(专用接口)都是为了实现 “对扩展开放,对修改关闭”;

  • 实现层:里氏替换是依赖倒转的前提 —— 如果子类不能替换父类,“针对抽象编程” 就会出现逻辑漏洞;合成复用是降低耦合的关键手段 —— 避免继承带来的强耦合,为开闭原则提供灵活性。

2. 实战优先级(按落地顺序)

优先级原则名称落地场景
1(必做)单一职责原则日常编码的类、方法拆分(如 Controller 按业务拆分、Service 按功能拆分)
2(必做)开闭原则需求变化时,优先新增代码而非修改(如新增支付方式、通知方式)
3(重点)依赖倒转原则架构设计时,高层模块依赖抽象(如 Service 依赖 DAO 接口、Controller 依赖 Service 接口)
4(重点)里氏替换原则子类设计时,不破坏父类约束(如扩展用户类型、订单类型时)
5(按需)接口隔离原则接口设计时,避免万能接口(如拆分用户接口、管理员接口)
6(按需)合成复用原则复用代码时,优先组合而非继承(如通知功能、日志功能的复用)

3. 常见误区:过度遵循原则

原则不是 “教条”,需结合业务场景灵活调整,避免 “为了原则而原则”:

  • 不用过度拆分职责:如一个简单的工具类(如DateUtils)包含 “日期格式化”“日期计算”,无需拆成两个类,因为它们都属于 “日期处理” 职责;

  • 不用过度抽象:如一个小型项目,无需为每个 Service 都定义接口 —— 抽象的成本(维护接口、实现类)可能高于收益;

  • 不用排斥继承:当子类与父类是明确的 “is-a” 关系且父类稳定时(如ArrayList extends AbstractList),继承比组合更简洁。

四、总结:设计原则的本质是 “平衡”

设计原则的核心不是 “写出完美的代码”,而是 “在需求多变与代码可维护之间找到平衡”—— 它允许你在初期快速落地业务,同时为后续迭代预留扩展空间。

记住:最好的设计不是遵循所有原则,而是在业务复杂度、开发效率、维护成本之间找到最优解。比如:

  • 小型项目 / 原型开发:优先保证单一职责、开闭原则,其他原则可简化(如不用定义过多接口);

  • 中大型项目 / 框架开发:需全面遵循 6 大原则,尤其是依赖倒转、接口隔离,为多团队协作、长期迭代提供基础;

  • 高频变化模块(如支付、优惠):重点关注开闭、依赖倒转、合成复用,确保需求变化时快速响应;

  • 稳定模块(如基础工具、数据模型):重点关注单一职责,保证逻辑简洁、可复用。

掌握设计原则,你不仅能看懂设计模式的 “为什么”,更能在没有设计模式的场景下,写出经得起迭代的高质量代码 —— 这才是设计原则的真正价值。


文章转载自:

http://pkY35H6i.mLfgx.cn
http://HFO0vGfX.mLfgx.cn
http://QYBXsmgg.mLfgx.cn
http://xoPG2bYi.mLfgx.cn
http://M4ETCQue.mLfgx.cn
http://zbgDz8ay.mLfgx.cn
http://BElH4PSh.mLfgx.cn
http://odr2Fx8O.mLfgx.cn
http://fQ2JGOyj.mLfgx.cn
http://J3C7ST3O.mLfgx.cn
http://r6o5mKSa.mLfgx.cn
http://nzZE9FRM.mLfgx.cn
http://aQWelq19.mLfgx.cn
http://kYAGTd2m.mLfgx.cn
http://eTqXgSm6.mLfgx.cn
http://E0INIgG6.mLfgx.cn
http://xxqPGMpS.mLfgx.cn
http://y73PalW7.mLfgx.cn
http://ibj9bXe2.mLfgx.cn
http://5RVKAmlL.mLfgx.cn
http://PEUj5zGa.mLfgx.cn
http://xG0LGoD5.mLfgx.cn
http://AIzT3W7F.mLfgx.cn
http://JCjFCoMk.mLfgx.cn
http://UwkCbPFa.mLfgx.cn
http://XZiSikPV.mLfgx.cn
http://zUovZ8r4.mLfgx.cn
http://B4J0zxxu.mLfgx.cn
http://5OWnZlZY.mLfgx.cn
http://mWdsQ85C.mLfgx.cn
http://www.dtcms.com/a/385022.html

相关文章:

  • 从零开始打造个性化浏览器导航扩展:极简高级风格设计
  • 软件包安装
  • QARM:Quantitative Alignment Multi-Modal Recommendation at Kuaishou
  • 通达信抓波段指标(主图)
  • Django基础环境入门
  • Java学习笔记2——简单语法
  • LLM-LLM大语言模型快速认识
  • Winogender:衡量NLP模型性别偏见的基准数据集
  • Oracle UNDO表空间使用率过高解决方案
  • Qt 中 OPC UA 通讯实战
  • 生产制造数智化
  • ensp配置学习笔记 比赛版 vlan 静态路由 ospf bgp dhcp
  • java-代码随想录第33天|62.不同路径、63.不同路径II
  • 突破限制:FileCodeBox远程文件分享新体验
  • 对讲机模块 TDD 噪音:原理、快速止噪解决方案
  • 知识点11:总线驱动的多Agent调度
  • 使用 Docker 搭建私有 PyPI 镜像仓库:支持多平台二进制包同步
  • HarmonyOS实现快递APP自动识别地址(国际版)
  • IPsec实验笔记
  • 工业IOT平台助力水泥集团实现数字化转型
  • 【CSS】图片自适应等比例缩放
  • Java 21 虚拟线程高并发落地全指南:中间件适配、场景匹配与细节优化的技术实践
  • 设计模式(C++)详解—适配器模式(1)
  • 圆周点生成的数学原理与Python实现
  • 牛客:校门外的树
  • JavaScript数据网格方案AG Grid 34.2 发布:更灵活的数据结构、更流畅的大数据交互与全新 UI 体验
  • U8g2库为XFP1116-07AY(128x64 OLED)实现菜单功能[ep:esp8266]
  • 软考-系统架构设计师 信息安全的保障体系与评估方法详细讲解
  • 第37章 AI伦理、安全与社会影响
  • 基于shell脚本实现mysql导出指定/全量表前n条,快速预览数据结构