设计模式——面向对象设计六大原则
摘要
本文详细介绍了设计模式中的六大基本原则,包括单一职责原则、开放封闭原则、里氏替换原则、接口隔离原则、依赖倒置原则和合成复用原则。每个原则都通过定义、理解、示例三个部分进行阐述,旨在帮助开发者提高代码的可维护性和灵活性。通过具体代码示例,文章展示了如何在实际项目中应用这些原则,以优化软件设计。
1. 单一职责原则
1.1. ✅ 定义:
一个类只负责一件事,有且仅有一个引起它变化的原因。
1.2. ✅ 理解:
这是单一职责原则(SRP)背后的核心动机:变化的原因越多,类的稳定性就越差,维护成本也就越高。如果一个类承担了太多职责,当其中一个职责变化时,可能会影响其他功能。
1.3. ✅ 示例
1.3.1. 职责=变化的原因
一个“职责”,本质上代表的是一个变化的原因。如果一个类承担了多种职责,它就会被多种不同的变化触发修改。
举例说明:
class ReportService {public void generateReport() {// 业务逻辑}public void saveToFile(String content) {// IO 文件保存逻辑}public void sendEmail(String content) {// 邮件发送逻辑}
}
这个类承担了 三种职责:
- 报表生成(业务变化时要改)
- 文件保存(存储方式变化时要改)
- 邮件发送(邮件策略变化时要改)
1.3.2. 职责之间强耦合,牵一发动全身
如果某天要变更邮件发送策略(如改用 Kafka 异步通知),你可能会:
- 改
sendEmail
方法; - 但如果修改失误或测试不足,可能会影响
generateReport
或saveToFile
方法的逻辑。
这就带来了:
- 不必要的风险(改一处,误伤其他);
- 不利于复用(不能只复用报表逻辑而不带邮件逻辑);
- 影响可测试性(一个测试类测试了多个功能)。
1.3.3. 职责分离后好处:解耦 + 高内聚
将不同职责分离成不同类:
class ReportGenerator {public String generateReport() { ... }
}class FileStorage {public void saveToFile(String content) { ... }
}class EmailNotifier {public void sendEmail(String content) { ... }
}
好处:
- 每个类只受一种变化影响;
- 修改一个模块不会误伤其他;
- 更容易测试、复用和维护;
- 符合高内聚、低耦合的设计理念。
2. 开放封闭原则(OCP:Open Closed Principle)
2.1. ✅ 定义:
对扩展开放,对修改封闭——允许对类行为的扩展,但不允许修改原有代码。
2.2. ✅ 理解:
通过接口、抽象类和多态机制,新增功能时不动旧代码,提升系统稳定性。也就是说,系统应该允许在不修改已有代码的前提下添加新功能,以提升稳定性、可维护性和可扩展性。通过抽象(接口/抽象类)定义稳定的扩展点,新功能只需新增实现类,通过多态机制接入,无需改动原有逻辑。抽象(接口/抽象类)+ 多态 = 构建扩展点,新增不改旧,系统更稳定。这是一种高质量、可持续演进的系统设计策略。
2.3. ✅ 示例:
假设你正在开发一个支付系统,最开始只支持微信支付:
// 早期版本
public class PaymentService {public void pay(String type) {if ("wechat".equals(type)) {System.out.println("微信支付");}}
}
缺点:
- 每增加一个支付方式(如支付宝、银行卡等),就要改动 pay 方法;
- 增加逻辑风险,测试成本提高,稳定性下降。
2.3.1. 面向抽象编程(重构)
// 抽象接口
public interface PayStrategy {void pay();
}// 微信支付实现
public class WeChatPay implements PayStrategy {public void pay() {System.out.println("微信支付");}
}// 支付宝支付实现
public class AlipayPay implements PayStrategy {public void pay() {System.out.println("支付宝支付");}
}// 上层调用
public class PaymentService {private PayStrategy payStrategy;public PaymentService(PayStrategy payStrategy) {this.payStrategy = payStrategy;}public void execute() {payStrategy.pay();}
}
2.3.2. 重构后好处:
- 新增支付方式,只需实现新的
PayStrategy
子类; PaymentService
不需要改动,遵循 开放-封闭原则;- 利用了接口+多态,实现功能扩展与旧代码解耦。
2.3.3. 应用场景
场景 | 抽象化方式 | 多态实现 | 示例说明 |
日志记录 |
|
| 新增日志方式无需修改旧逻辑 |
排序策略 |
| 自定义 | 支持多种排序方式 |
消息推送 |
|
| 扩展渠道不影响已有逻辑 |
业务规则引擎 |
| 各种规则类 | 增加规则时只需新增类,不动主流程代码 |
3. 里氏替换原则(LSP:Liskov Substitution Principle)
3.1. ✅ 定义:
子类必须能够替换父类,程序逻辑的正确性不被破坏。
3.2. ✅ 理解:
子类继承父类时,不应改变父类原有功能的语义,否则违背了替换原则。子类在继承父类时,不能违背父类原有的语义和行为约定,否则就破坏了继承的正确性。如果一个子类违背了父类的行为预期,那么它就不能被替换为父类使用,会导致系统运行异常或逻辑错误。
3.3. ✅ 示例:
3.3.1. 不符合 LSP 的示例(反例)
场景:设计一个“矩形”和“正方形”的类。
class Rectangle {protected int width;protected int height;public void setWidth(int w) { this.width = w; }public void setHeight(int h) { this.height = h; }public int getArea() {return width * height;}
}
正方形继承矩形:
class Square extends Rectangle {@Overridepublic void setWidth(int w) {this.width = w;this.height = w; // 强行同步宽高}@Overridepublic void setHeight(int h) {this.height = h;this.width = h; // 强行同步宽高}
}
问题点:
Rectangle r = new Square();
r.setWidth(4);
r.setHeight(5);
System.out.println(r.getArea()); // 原预期是 4 * 5 = 20,但实际输出 25!
你以为你用的是 Rectangle,但行为却是 Square 强行同步宽高,导致语义变化,替换失败,这就违反了 LSP。
3.3.2. 符合 LSP 的示例(正例)
解决方式是:将 Rectangle
和 Square
分开设计,不要使用继承,而是将“正方形”作为特殊矩形逻辑的聚合或组合。
interface Shape {int getArea();
}class Rectangle implements Shape {protected int width;protected int height;public Rectangle(int w, int h) {this.width = w;this.height = h;}public int getArea() {return width * height;}
}class Square implements Shape {private int side;public Square(int side) {this.side = side;}public int getArea() {return side * side;}
}
这样你就不会被继承关系“误导”。总结一句话:不要为了代码复用而继承,如果子类不能完美遵守父类的行为契约,就不应该继承它。符合里氏替换原则能带来:继承结构的健壮性;多态替换的可靠性;系统运行的一致性。
4. 接口隔离原则(ISP:Interface Segregation Principle)
4.1. ✅ 定义:
不应该强迫客户端依赖它不需要的接口;一个接口最好只包含客户端所需的方法。
4.2. ✅ 理解:
一个接口最好不要太“大” —— 拆分成小而精的多个接口,避免“胖接口”。
“胖接口”是指一个接口中定义了过多的方法,导致:
- 实现类必须实现一些无关方法;
- 实现代码中出现大量的空方法、无意义实现;
- 模块间耦合度增加,影响代码可维护性、扩展性。
4.3. ✅ 示例:
4.3.1. ❌ 反例:一个“胖接口”
public interface Animal {void eat();void fly();void swim();void run();
}
如果我们要实现一个 Dog
:
public class Dog implements Animal {public void eat() { System.out.println("吃"); }public void fly() { } // 狗不会飞public void swim() { System.out.println("狗刨"); }public void run() { System.out.println("跑"); }
}
这就是接口污染:被迫实现不需要的 fly() 方法,不符合 ISP。
4.3.2. ✅ 正例:拆分为多个小接口
public interface Eater {void eat();
}public interface Flyer {void fly();
}public interface Swimmer {void swim();
}public interface Runner {void run();
}
实现类只依赖自己关心的接口:
public class Dog implements Eater, Swimmer, Runner {public void eat() { System.out.println("吃"); }public void swim() { System.out.println("狗刨"); }public void run() { System.out.println("跑"); }
}
这样:
- 每个接口职责单一;
- 实现类更清晰;
- 系统更易扩展、测试、维护。
4.3.3. ✅ 现实应用场景举例
场景 | 粗接口(不推荐) | 拆分小接口(推荐) |
文件操作工具类 |
|
|
用户权限管理接口 |
同时包含注册、登录、授权、查询 |
|
Spring Data Repository | 如果某个 DAO 接口包含不常用的高级查询方法 | 使用继承自 |
5. 依赖倒置原则(DIP:Dependency Inversion Principle)
5.1. ✅ 定义:
高层模块不应该依赖低层模块,二者都应该依赖抽象;抽象不应该依赖细节,细节应该依赖抽象。
5.2. ✅ 理解:
依赖“抽象”(接口或抽象类),不要直接依赖具体实现类,利于扩展与测试。
- 程序中模块之间通过“抽象”来交互;
- 不要在高层业务代码中直接依赖具体实现类;
- 通过接口/抽象类定义行为,由具体类实现。
为什么需要依赖倒置?
- 增强可扩展性:替换或扩展底层实现时,不需要修改上层代码;
- 便于测试:接口更容易被 mock,实现单元测试;
- 解耦:高层和低层只通过抽象耦合。
5.3. ✅ 示例:
5.3.1. ❌ 反例:高层直接依赖低层实现
class MySQLUserDao {public void save(String name) {System.out.println("保存用户到MySQL:" + name);}
}class UserService {private MySQLUserDao dao = new MySQLUserDao(); // 直接依赖实现类public void createUser(String name) {dao.save(name);}
}
UserService
只能使用MySQLUserDao
;- 无法替换成其他数据源(如 Redis、Mongo);
- 单元测试困难。
5.3.2. ✅ 正例:依赖接口
// 抽象
public interface UserDao {void save(String name);
}// 实现
public class MySQLUserDao implements UserDao {public void save(String name) {System.out.println("保存用户到MySQL:" + name);}
}// 高层只依赖接口
public class UserService {private final UserDao dao;public UserService(UserDao dao) {this.dao = dao;}public void createUser(String name) {dao.save(name);}
}
这样 UserService
就与实现无关了,你可以注入任何实现:
new UserService(new MySQLUserDao());
new UserService(new MockUserDao());
5.3.3. ✅ Spring 中的依赖倒置实践
Spring 框架本身就是依赖倒置原则的典范:
- 通过
@Autowired
、构造器注入等,注入接口而非实现; - 利用 IOC 容器控制实现类选择;
- 通过配置文件/注解进行行为替换,无需改动业务代码。
@Service
public class UserService {@Autowiredprivate final UserRepository userRepository;
}
6. 合成复用原则(CARP:Composition Over Inheritance)
6.1. ✅ 定义:
优先使用“组合”或“聚合”来复用代码,而不是继承。
6.2. ✅ 理解:
继承是强耦合,组合更加灵活,符合“变化点隔离”的设计思想。
机制 | 特点简述 |
继承 | 是“is-a”关系,子类拥有父类所有行为,强耦合,不灵活 |
组合 | 是“has-a”关系,通过属性组合对象,松耦合,更灵活 |
聚合 | 是“has-a”的一种特殊情况,组合关系中对象生命周期独立 |
6.3. ✅ 示例:
6.3.1. ❌ 继承的问题
- 子类会继承父类的所有方法,哪怕有些不需要;
- 一旦父类修改,所有子类可能都会受影响;
- Java 不支持多继承,扩展受限;
- 难以满足未来需求的变化。
例:
class Animal {void walk() { System.out.println("动物走"); }
}class Bird extends Animal {void fly() { System.out.println("鸟飞"); }
}
现在你想做一个企鹅(企鹅不会飞),怎么办?继承 Bird
显然不合适,但重新写又代码重复。
6.3.2. ✅ 组合的优点
- 可以灵活地引入所需能力;
- 符合变化点隔离原则,不同功能独立演化;
- 可以更好地应对业务场景变化。
6.3.3. ✅ 示例:用组合代替继承
1. 把行为抽象成接口
interface Flyable {void fly();
}interface Walkable {void walk();
}
2. 抽离行为实现类
class NormalWalk implements Walkable {public void walk() { System.out.println("用两条腿走"); }
}class NoFly implements Flyable {public void fly() { System.out.println("我不会飞"); }
}
3. 组合行为到企鹅类中
class Penguin {private Walkable walkBehavior;private Flyable flyBehavior;public Penguin(Walkable walk, Flyable fly) {this.walkBehavior = walk;this.flyBehavior = fly;}public void walk() {walkBehavior.walk();}public void fly() {flyBehavior.fly();}
}
4. 使用
Penguin penguin = new Penguin(new NormalWalk(), new NoFly());
penguin.walk(); // 用两条腿走
penguin.fly(); // 我不会飞
6.3.4. 🔧 总结对比
对比点 | 继承 | 组合 |
耦合度 | 高(父类变,子类易受影响) | 低(只依赖接口/对象) |
灵活性 | 不支持多继承 | 可以组合多个不同功能 |
可测试性 | 不易 mock | 易于注入和 mock |
改动影响面 | 广 | 局部可控 |
设计哲学 | 强制共享行为 | 按需装配功能 |
7. 项目实践怎么遵循设计原则
7.1. 软件设计是一个逐步优化的过程
从上面六个原则的讲解中,应该体会到软件的设计是一个循序渐进,逐步优化的过程。经过一次次的逻辑分析,一层层的结构调整和优化,最终得出一个较为合理的设计图。整个动物世界的类图如下:
我们对上面五个原则做一个总结:
- 单一职责原则告诉我们实现类要职责单一。用于类的设计,增加一个类时使用 SRP 原则来核对该类的设计是否纯粹干净,也就是让一个类的功能尽可能单一,不要想着一个类包揽所有功能。
- 里氏替换原则告诉我们不要破坏继承体系。用于指导类继承的设计,设计类之间的继承关系时,使用 LSP 原则来判断这种继承关系是否合理。只要父类能出现的地方子类就能出现(就可以用子类来替换他),反之则不一定成立。
- 依赖倒置原则告诉我们要面向接口编程。用于指导如何抽象,即要依赖抽象和接口编程,不要依赖具体的实现。
- 接口隔离原则告诉我们在设计接口的时候要精简单一。用于指导接口的设计,当发现一个接口过于臃肿时,就要对这个接口进行适当的拆分。
- 开放封闭原则告诉我们要对扩展开放,对修改关闭。开闭原则可以说是整个设计的最终目标和原则!开闭原则是总纲,其他4个原则是对这个原则具体解释。
设计原则是进行软件设计的核心思想和规范。那在实际的项目开发中,是否一定要遵循原则?答案不总是肯定,要视情况而定。因为在实际的项目开发中,必须要安时按量地完成任务。项目的进度受时间成本,测试资源的影响,而且程序一定要保存稳定可以。
还记得我们在单一职责原则中提到一个例子吗?面对需求的变更,我们有三种解决方式:
- 方法一:直接改原有的函数(方法),这种方式最快速,但后期维护最困难,而且不便拓展;这种方式一定是要杜绝的。
- 方法二:增加一个新方法,不修改原有的方法,这在方法级别是符合单一职责原则的;但对上层的调用会增加不少麻烦。在项目比较复杂,类比较庞大,而且测试资源比较紧缺的时候,不失为一种快速和稳妥的方式。因为如果要进行大范围的代码重构,势必要对影响到的模块进行全覆盖的测试回归,才能确保系统的稳定可靠。
- 方法三:增加一个新的类来负责新的职责,两个职责分离,这是符合单一职责原则的。在项目首次开发,或逻辑相对简单的情况下,需要采用这种方式。
在实际的项目开发中,我们要尽可能地遵循这些设计原则。但并不是要 100% 地遵从,需要结果实际的时间成本、测试资源、代码改动难度等情况进行综合评估,适当取舍,采用最高效合理的方式。
博文参考
《软件设计模式》
相关文章:

设计模式——面向对象设计六大原则
摘要 本文详细介绍了设计模式中的六大基本原则,包括单一职责原则、开放封闭原则、里氏替换原则、接口隔离原则、依赖倒置原则和合成复用原则。每个原则都通过定义、理解、示例三个部分进行阐述,旨在帮助开发者提高代码的可维护性和灵活性。通过具体代码…...

Python制作史莱姆桌面宠物!可爱的
史莱姆桌面宠物 一个可爱的桌面史莱姆宠物,它会在您的任务栏上移动并提供可视化设置界面。 这里写目录标题 史莱姆桌面宠物功能特点安装与运行直接运行方式创建可执行文件 使用说明自定义GIF说明打包说明开源地址 功能特点 可爱的史莱姆在任务栏上自动移动支持…...
React hook之userReducer
在 React 中,useReducer 是一个用于管理复杂状态逻辑的 Hook,它类似于 Redux 中的 reducer 模式,但更轻量且适用于组件内部或结合 Context API 实现全局状态管理。以下是 useReducer 的详细用法指南: 1. 基本语法 const [state, …...

Dify源码教程:账户和密码传递分析
概述 Dify系统中账户创建过程中的密码处理是Web应用安全的重要环节。本教程详细分析了从前端表单到后端存储的完整流程,展示了Dify如何安全地处理用户凭据。 前端部分 在 dify/web/app/install/installForm.tsx 文件中,当用户填写完表单并点击安装按钮…...
如果科技足够发达,是否还需要维持自然系统(例如生物多样性)中那种‘冗余’和‘多样性’,还是可以只保留最优解?
这是一个非常深刻的问题,触及到了进化生物学、复杂系统理论和未来科技哲学的交汇点。 你可以这样理解这个问题的结构: “如果科技足够发达,是否还需要维持自然系统(例如生物多样性)中那种‘冗余’和‘多样性’&#x…...

数据分析图表类型及其应用场景
说明:顶部HTML文件下载后可以直接查看,带有示图。 摘要 数据可视化作为现代数据分析的核心环节,旨在将复杂、抽象的数据转化为直观、易懂的图形形式。这种转化显著提升了业务决策能力,优化了销售与营销活动,开辟了新…...
第四十二天打卡
知识点回顾 回调函数lambda函数hook函数的模块钩子和张量钩子Grad-CAM的示例 作业:理解下今天的代码即可 # 定义一个回调函数 def handle_result(result):"""处理计算结果的回调函数"""print(f"计算结果是: {result}")# 定…...

Github 2025-06-03Python开源项目日报 Top10
根据Github Trendings的统计,今日(2025-06-03统计)共有10个项目上榜。根据开发语言中项目的数量,汇总情况如下: 开发语言项目数量Python项目10Rust项目1HTML项目1C项目1 系统设计指南 创建周期:2507 天开发语言:Pyt…...
Vim查看文件十六进制方法
在 Vim 中查看文件的十六进制格式,可以通过以下步骤实现: 方法 1:使用内置命令(无需插件) 用 Vim 以二进制模式打开文件: vim -b 文件名或打开文件后执行: :set binary转换为十六进制视图&…...

电脑提示dll文件缺失怎么办 dll修复方法
当你在使用某些应用程序或启动电脑时,看到提示“DLL文件缺失”的错误信息,这通常意味着某个必要的动态链接库(DLL)文件无法被找到或加载,导致软件无法正常运行。本文将详细介绍如何排查和修复DLL文件缺失的问题&#x…...

【自动思考记忆系统】demo (Java版)
背景:看了《人工智能》中的一段文章,于是有了想法。想从另一种观点(⭕️)出发,尝试编码,告别传统程序员一段代码解决一个问题的方式。下图是文章原文和我的思考涂鸦✍️,于是想写一个自动思考记…...
【AAOS】【源码分析】用户管理(二)-- 整体架构
整体介绍 Android多用户功能作为 Android Automotive 的重要组成部分,为不同驾驶员和乘客提供了一个更加定制化、隐私保护的使用环境。Android 多用户的存在,它可以让多个用户使用同一台设备,同时保持彼此的数据、应用和设置分隔开来。 各用户类型的权限 能力SystemAdminS…...

51单片机基础部分——独立按键检测
前言 在单片机开发中,我们会经常对单片机的状态进行控制,比如我们会控制某个灯点亮,某个灯熄灭,这个时候我们就要开始做控制,我们可以通过什么控制呢,这个地方我们选择按键控制 按键实物及工作原理 生活…...

【Docker管理工具】部署Docker可视化管理面板Dpanel
【Docker管理工具】部署Docker可视化管理面板Dpanel 一、Dpanel介绍1.1 DPanel 简介1.2 主要特点 二、本次实践规划2.1 本地环境规划2.2 本次实践介绍 三、本地环境检查3.1 检查Docker服务状态3.2 检查Docker版本3.3 检查docker compose 版本 四、下载Dpanel镜像五、部署Dpanel…...
Github 2025-06-02 开源项目周报 Top11
根据Github Trendings的统计,本周(2025-06-02统计)共有11个项目上榜。根据开发语言中项目的数量,汇总情况如下: 开发语言项目数量Python项目6Jupyter Notebook项目2Shell项目1Dockerfile项目1TypeScript项目1Vue项目1PowerShell项目1MindsDB:定制企业数据人工智能的开源平台…...

springboot实现查询学生
文章目录 数据库前端 请求mybatis 数据库 前端 请求 <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><title>Title</title> </head> <body> <a href"/list">启动学生管理…...
深入解析C++五大常用设计模式:原理、实现与应用场景
设计模式是解决特定软件设计问题的经典方案,掌握它们能显著提升代码的可维护性和扩展性。本文详细解析C中五种最常用的设计模式,附带完整代码示例和实战技巧。 一、设计模式概述 设计模式是面向对象编程中可复用的解决方案,它们源于工程师们…...
标识符Symbol和迭代器的实现
Symbol基础 Symbol("描述") 创建唯一标识符(每次调用返回新值) Symbol.for("key") 全局注册表模式(相同key返回同一Symbol) Symbol特性 作为对象属性键时:obj[SymbolKey] value不参与常规遍历&…...

Appium+python自动化(九)- 定位元素工具
简介 环境搭建好了,其他方面的知识也准备的差不多了,那么就开始下一步元素定位,元素定位主要介绍如何使用uiautomatorviewer,通过定位到页面上的元素,然后进行相应的点击等操作. 此外在介绍另一款工具:Insp…...

Unity 中实现可翻页的 PageView
之前已经实现过: Unity 中实现可复用的 ListView-CSDN博客文章浏览阅读5.6k次,点赞2次,收藏27次。源码已放入我的 github,地址:Unity-ListView前言实现一个列表组件,表现方面最核心的部分就是重写布局&…...
clickhouse常用语句汇总——持续更新中
一、查询判断是否包含指定列 1.根据数据库,表名查看表包含的列 SELECT name FROM system.columns WHERE table table_name AND database databasename;2.查找指定列target_column是否是表table_name的列 SELECT count() > 0 AS column_exists FROM system…...

云计算 Linux Rocky day05【rpm、yum、history、date、du、zip、ln】
云计算 Linux Rocky day05【rpm、yum、history、date、du、zip、ln】 目录 云计算 Linux Rocky day05【rpm、yum、history、date、du、zip、ln】1.RPM包的一般安装位置2.软件名和软件包名3.查询软件信息4.查询软件包5.导入红帽签名信息,解决查询软件包信息报错6.利用…...

LuaJIT2.1 和 Lua5.4.8 性能对比
说明 最近在学习 LuaJIT,想看看把它接入到项目中使用,会提高多大的性能。 今天抽时间,简单地测试了一下 LuaJIT 2.2 和 Lua5.4.8 的性能。 测试平台: 系统:Windows 10 WSLCPU:Intel Core™ i7-8700 CPU…...
深度学习姿态估计实战:基于ONNX Runtime的YOLOv8 Pose部署全解析
本文将详细介绍如何脱离YOLO官方环境,使用ONNX Runtime部署YOLOv8姿态估计模型。内容包括模型加载、图像预处理(Letterbox缩放和填充)、推理执行、输出解码(边界框和关键点处理)、非极大值抑制(NMS…...
深度探索:如何用DeepSeek重构你的工作流
前言:AI时代的工作革命 在人工智能浪潮席卷的今天,DeepSeek作为国产大模型的代表之一,正以其强大的自然语言处理能力、代码生成能力和多模态交互特性,重新定义着人类的工作方式。根据IDC报告显示,2024年企业级AI应用市场规模已突破800亿美元,其中智能办公场景占比达32%,…...

深入解析与解决方案:处理Elasticsearch中all found copies are either stale or corrupt未分配分片问题
目录 引言 1 问题诊断深入分析 1.1 错误含义深度解析 1.2 获取详细的诊断信息 2 解决方案选择与决策流程 2.1 可用选项全面对比 2.2 推荐处理流程与决策树 3 具体操作步骤详解 3.1 优先尝试 - 分配最新副本(最低风险) 3.2 中等风险方案 - 分配…...

【NLP 78、手搓Transformer模型结构】
你以为走不出的淤泥,也迟早会云淡风轻 —— 25.5.31 引言 ——《Attention is all you need》 《Attention is all you need》这篇论文可以说是自然语言处理领域的一座里程碑,它提出的 Transformer 结构带来了一场技术革命。 研究背景与目标 在 Transfo…...
yum更换阿里云的镜像源
步骤 1:备份原有源配置(重要!) sudo mkdir /etc/yum.repos.d/backup sudo mv /etc/yum.repos.d/CentOS-* /etc/yum.repos.d/backup/步骤 2:下载阿里云源配置 sudo curl -o /etc/yum.repos.d/CentOS-Base.repo https:…...

如何自定义WordPress主题(5个分步教程)
如果您已经安装了一个 WordPress 主题,但它不太适合您,您可能会感到沮丧。在定制 WordPress 主题方面,您有很多选择。 挑战在于找到正确的方法。 在本篇文章中,我将引导您了解自定义 WordPress 主题的各种选项,帮助您…...
ios版本的Tiktok二次安装不上,提示:Unable to Install “TikTok”
问题:Domain: IXUserPresentableErrorDomain Code: 1 Recovery Suggestion: Failed to load Info.plist from bundle at path /private/var/containers/Bundle/Application/E99D86D4-F96E-48F9-86C5-FE095A22E13A/DouyinDev.app/PlugIns/AwemeNotificationService.a…...