C++八股 —— 设计模式

文章目录

    • 一、创建型模式
      • 1. 单例模式
      • 2. 工厂模式
    • 二、结构型模式
      • 1. 装饰器模式
      • 2. 代理模式
    • 三、行为型模式
      • 1. 观察者模式
      • 2. 策略模式

一、创建型模式

1. 单例模式

C++八股 —— 单例模式_c++ 单例模式-CSDN博客

2. 工厂模式

参考:【设计模式】工厂模式详解-----简单工厂模式、工厂方法模式、抽象工厂模式-CSDN博客

什么是工厂模式

工厂模式是一种创建型设计模式,它提供了一种创建对象的最佳方式,而无需暴露对象创建的逻辑细节。

工厂模式的三种类型

  1. 简单工厂模式:一个工厂类根据传入的参数决定创建哪种产品类的实例
  2. 工厂方法模式:定义一个创建对象的接口,但让子类决定实例化哪个类
  3. 抽象工厂模式:提供一个创建一系列相关或相互依赖对象的接口,而无需指定它们具体的类

工厂模式的优点

  1. 封装创建逻辑:将对象的创建与使用分离
  2. 代码解耦:客户端代码不需要知道具体产品类的类名
  3. 易于扩展:添加新产品时,只需扩展工厂类,符合开闭原则
  4. 统一管理:可以对对象的创建进行统一的管理和控制

适用场景

  1. 当一个类不知道它所必须创建的对象的类时
  2. 当一个类希望由其子类来指定它所创建的对象时
  3. 当类将创建对象的职责委托给多个帮助子类中的某一个,并且你希望将哪一个帮助子类是代理者这一信息局部化时

简单工程模式示例

#include <iostream>
#include <string>
#include <memory>// 产品接口
class Shape {
public:virtual void draw() = 0;virtual ~Shape() {}
};// 具体产品类
class Circle : public Shape {
public:void draw() override {std::cout << "Drawing a Circle" << std::endl;}
};class Rectangle : public Shape {
public:void draw() override {std::cout << "Drawing a Rectangle" << std::endl;}
};class Triangle : public Shape {
public:void draw() override {std::cout << "Drawing a Triangle" << std::endl;}
};// 简单工厂
class ShapeFactory {
public:static std::unique_ptr<Shape> createShape(const std::string& shapeType) {if (shapeType == "CIRCLE") {return std::make_unique<Circle>();} else if (shapeType == "RECTANGLE") {return std::make_unique<Rectangle>();} else if (shapeType == "TRIANGLE") {return std::make_unique<Triangle>();}return nullptr;}
};int main() {// 使用工厂创建对象auto circle = ShapeFactory::createShape("CIRCLE");auto rectangle = ShapeFactory::createShape("RECTANGLE");auto triangle = ShapeFactory::createShape("TRIANGLE");circle->draw();rectangle->draw();triangle->draw();return 0;
}

工厂方法模式

#include <iostream>
#include <memory>// 产品接口
class Button {
public:virtual void render() = 0;virtual void onClick() = 0;virtual ~Button() {}
};// 具体产品
class WindowsButton : public Button {
public:void render() override {std::cout << "Rendering a Windows button" << std::endl;}void onClick() override {std::cout << "Windows button clicked" << std::endl;}
};class WebButton : public Button {
public:void render() override {std::cout << "Rendering a Web button" << std::endl;}void onClick() override {std::cout << "Web button clicked" << std::endl;}
};// 创建者类
class Dialog {
public:virtual std::unique_ptr<Button> createButton() = 0;void render() {auto button = createButton();button->render();button->onClick();}virtual ~Dialog() {}
};// 具体创建者
class WindowsDialog : public Dialog {
public:std::unique_ptr<Button> createButton() override {return std::make_unique<WindowsButton>();}
};class WebDialog : public Dialog {
public:std::unique_ptr<Button> createButton() override {return std::make_unique<WebButton>();}
};int main() {std::unique_ptr<Dialog> dialog;// 根据配置或环境选择创建者std::string config = "Windows"; // 可以改为 "Web" 来测试if (config == "Windows") {dialog = std::make_unique<WindowsDialog>();} else if (config == "Web") {dialog = std::make_unique<WebDialog>();}if (dialog) {dialog->render();}return 0;
}

抽象工程模式

#include <iostream>
#include <memory>// 抽象产品A
class Checkbox {
public:virtual void paint() = 0;virtual ~Checkbox() {}
};// 具体产品A1
class WindowsCheckbox : public Checkbox {
public:void paint() override {std::cout << "Rendering a Windows checkbox" << std::endl;}
};// 具体产品A2
class WebCheckbox : public Checkbox {
public:void paint() override {std::cout << "Rendering a Web checkbox" << std::endl;}
};// 抽象产品B
class Button {
public:virtual void paint() = 0;virtual ~Button() {}
};// 具体产品B1
class WindowsButton : public Button {
public:void paint() override {std::cout << "Rendering a Windows button" << std::endl;}
};// 具体产品B2
class WebButton : public Button {
public:void paint() override {std::cout << "Rendering a Web button" << std::endl;}
};// 抽象工厂
class GUIFactory {
public:virtual std::unique_ptr<Button> createButton() = 0;virtual std::unique_ptr<Checkbox> createCheckbox() = 0;virtual ~GUIFactory() {}
};// 具体工厂1
class WindowsFactory : public GUIFactory {
public:std::unique_ptr<Button> createButton() override {return std::make_unique<WindowsButton>();}std::unique_ptr<Checkbox> createCheckbox() override {return std::make_unique<WindowsCheckbox>();}
};// 具体工厂2
class WebFactory : public GUIFactory {
public:std::unique_ptr<Button> createButton() override {return std::make_unique<WebButton>();}std::unique_ptr<Checkbox> createCheckbox() override {return std::make_unique<WebCheckbox>();}
};// 客户端代码
class Application {
private:std::unique_ptr<GUIFactory> factory;std::unique_ptr<Button> button;std::unique_ptr<Checkbox> checkbox;public:Application(std::unique_ptr<GUIFactory> f) : factory(std::move(f)) {}void createUI() {button = factory->createButton();checkbox = factory->createCheckbox();}void paint() {if (button) button->paint();if (checkbox) checkbox->paint();}
};int main() {std::string config = "Windows"; // 可以改为 "Web" 来测试std::unique_ptr<GUIFactory> factory;if (config == "Windows") {factory = std::make_unique<WindowsFactory>();} else if (config == "Web") {factory = std::make_unique<WebFactory>();}if (factory) {auto app = Application(std::move(factory));app.createUI();app.paint();}return 0;
}

二、结构型模式

1. 装饰器模式

核心思想动态地给一个对象添加一些额外的职责,而无需通过子类继承。它通过创建一个包装对象(即装饰器)来包裹真实对象,提供了比继承更有弹性的替代方案。

比喻:就像给一个礼物打包。你可以先装盒子,再系丝带,最后贴卡片。每个步骤都是在原有礼物的基础上“装饰”新的功能,而不是改变礼物本身。

优点

  • 无需创建大量子类即可扩展功能。
  • 可以在运行时动态地添加或撤销功能。
  • 符合“开闭原则”(对扩展开放,对修改关闭)。

C++ 样例
我们有一个简单的Stream接口,我们需要动态地为其添加压缩和加密的功能。

#include <iostream>
#include <string>// 组件接口
class Stream {
public:virtual void write(const std::string& data) = 0;virtual ~Stream() {}
};// 具体组件
class FileStream : public Stream {
public:void write(const std::string& data) override {std::cout << "Writing \"" << data << "\" to a file." << std::endl;}
};// 装饰器基类
class StreamDecorator : public Stream {
protected:Stream* m_stream; // 持有一个组件对象的引用
public:StreamDecorator(Stream* stream) : m_stream(stream) {}virtual ~StreamDecorator() { delete m_stream; }
};// 具体装饰器 - 压缩
class CompressedStream : public StreamDecorator {
public:CompressedStream(Stream* stream) : StreamDecorator(stream) {}void write(const std::string& data) override {std::string compressedData = "Compressed(" + data + ")";m_stream->write(compressedData); // 调用被装饰对象的方法}
};// 具体装饰器 - 加密
class EncryptedStream : public StreamDecorator {
public:EncryptedStream(Stream* stream) : StreamDecorator(stream) {}void write(const std::string& data) override {std::string encryptedData = "Encrypted(" + data + ")";m_stream->write(encryptedData); // 调用被装饰对象的方法}
};int main() {// 1. 简单的文件流Stream* stream1 = new FileStream();stream1->write("Hello World");delete stream1;std::cout << "---------------" << std::endl;// 2. 动态添加功能:压缩的文件流Stream* stream2 = new CompressedStream(new FileStream());stream2->write("Hello World");delete stream2;std::cout << "---------------" << std::endl;// 3. 动态添加更多功能:先加密再压缩的文件流// 装饰顺序很重要!Stream* stream3 = new CompressedStream(new EncryptedStream(new FileStream()));stream3->write("Hello World");delete stream3;return 0;
}

输出

Writing "Hello World" to a file.
---------------
Writing "Compressed(Hello World)" to a file.
---------------
Writing "Compressed(Encrypted(Hello World))" to a file.

2. 代理模式

核心思想:为另一个对象提供一个替身或占位符以控制对这个对象的访问。

常见代理类型

  • 远程代理:为一个对象在不同的地址空间提供局部代表(例如,RPC调用)。
  • 虚拟代理:根据需要创建开销很大的对象(如图片懒加载)。
  • 保护代理:控制对原始对象的访问权限。
  • 智能引用代理:在对象被访问时执行附加操作(如引用计数、日志记录)。

C++ 样例
虚拟代理:延迟加载大图片。

#include <iostream>
#include <string>// 抽象主题
class Image {
public:virtual void display() = 0;virtual ~Image() {}
};// 真实主题
class RealImage : public Image {
private:std::string m_filename;void loadFromDisk() {std::cout << "Loading image: " << m_filename << " (This is an expensive operation!)" << std::endl;}
public:RealImage(const std::string& filename) : m_filename(filename) {loadFromDisk();}void display() override {std::cout << "Displaying image: " << m_filename << std::endl;}
};// 代理
class ProxyImage : public Image {
private:std::string m_filename;RealImage* m_realImage; // 代理持有一个对真实对象的引用public:ProxyImage(const std::string& filename) : m_filename(filename), m_realImage(nullptr) {}~ProxyImage() { delete m_realImage; }void display() override {// 只有在需要时才创建真实对象if (m_realImage == nullptr) {m_realImage = new RealImage(m_filename);}// 委托给真实对象执行请求m_realImage->display();}
};int main() {// 创建代理时,真实对象尚未创建,没有昂贵的加载操作Image* image = new ProxyImage("test_10MB_photo.jpg");std::cout << "Image object created. Image not loaded yet." << std::endl;// 第一次调用display,真实对象被创建和加载image->display();std::cout << std::endl;// 后续调用,真实对象已存在,直接使用std::cout << "Second display call:" << std::endl;image->display();delete image;return 0;
}

输出

Image object created. Image not loaded yet.
Loading image: test_10MB_photo.jpg (This is an expensive operation!)
Displaying image: test_10MB_photo.jpgSecond display call:
Displaying image: test_10MB_photo.jpg

三、行为型模式

1. 观察者模式

核心思想:定义对象间的一种一对多的依赖关系,当一个对象(主题)的状态发生改变时,所有依赖于它的对象(观察者)都得到通知并被自动更新。又称“发布-订阅”模式。

比喻:报纸订阅。出版社(主题)负责出版报纸。你(观察者)向出版社订阅后,一旦有新报纸出版,出版社就会自动送到你家。你也可以随时取消订阅。

C++ 样例
使用现代C++的特性实现。

#include <iostream>
#include <vector>
#include <memory>
#include <algorithm>// 观察者接口
class Observer {
public:virtual void update(int temperature) = 0;virtual ~Observer() {}
};// 主题(被观察者)
class WeatherStation {
private:int m_temperature;std::vector<Observer*> m_observers; // 存储观察者指针public:void registerObserver(Observer* observer) {m_observers.push_back(observer);}void removeObserver(Observer* observer) {m_observers.erase(std::remove(m_observers.begin(), m_observers.end(), observer),m_observers.end());}void notifyObservers() {for (auto observer : m_observers) {observer->update(m_temperature);}}void setTemperature(int temp) {m_temperature = temp;std::cout << "Temperature updated to: " << temp << std::endl;notifyObservers(); // 状态改变,通知所有观察者}
};// 具体观察者
class Display : public Observer {
public:void update(int temperature) override {std::cout << "[Display] Current temperature is: " << temperature << "°C" << std::endl;}
};class AlertSystem : public Observer {
public:void update(int temperature) override {if (temperature > 30) {std::cout << "[AlertSystem] Warning! Temperature is too high: " << temperature << "°C" << std::endl;}}
};int main() {WeatherStation station;Display display;AlertSystem alert;// 注册观察者station.registerObserver(&display);station.registerObserver(&alert);// 改变主题状态,触发通知station.setTemperature(25);std::cout << "-------------------" << std::endl;station.setTemperature(35);// 移除一个观察者station.removeObserver(&alert);std::cout << "-------------------" << std::endl;std::cout << "After removing alert system:" << std::endl;station.setTemperature(40);return 0;
}

输出

Temperature updated to: 25
[Display] Current temperature is: 25°C
[AlertSystem] Warning! Temperature is too high: 25°C
-------------------
Temperature updated to: 35
[Display] Current temperature is: 35°C
[AlertSystem] Warning! Temperature is too high: 35°C
-------------------
After removing alert system:
Temperature updated to: 40
[Display] Current temperature is: 40°C

2. 策略模式

核心思想:定义一系列算法,将每个算法封装起来,并且使它们可以互相替换。策略模式让算法的变化独立于使用算法的客户。

比喻:出行方式。去机场是一个目标(Context),你可以选择不同的策略(Strategy):坐公交、打车、坐地铁。你可以根据时间、金钱等因素轻松替换策略,而改变“去机场”这个行为本身。

优点

  • 避免使用多重条件判断语句(if-else/switch-case)。
  • 算法可以自由切换和扩展。
  • 符合“开闭原则”。

C++ 样例

#include <iostream>
#include <memory>
#include <vector>// 策略接口
class PaymentStrategy {
public:virtual void pay(int amount) = 0;virtual ~PaymentStrategy() {}
};// 具体策略
class CreditCardPayment : public PaymentStrategy {
private:std::string m_name;std::string m_cardNumber;
public:CreditCardPayment(const std::string& name, const std::string& cardNumber): m_name(name), m_cardNumber(cardNumber) {}void pay(int amount) override {std::cout << "Paid $" << amount << " using Credit Card (" << m_cardNumber << ")" << std::endl;}
};class PayPalPayment : public PaymentStrategy {
private:std::string m_email;
public:PayPalPayment(const std::string& email) : m_email(email) {}void pay(int amount) override {std::cout << "Paid $" << amount << " using PayPal (" << m_email << ")" << std::endl;}
};class CryptoPayment : public PaymentStrategy {
private:std::string m_walletAddress;
public:CryptoPayment(const std::string& address) : m_walletAddress(address) {}void pay(int amount) override {std::cout << "Paid $" << amount << " using Crypto (Address: " << m_walletAddress << ")" << std::endl;}
};// 上下文(Context)
class ShoppingCart {
private:std::vector<std::string> m_items;std::unique_ptr<PaymentStrategy> m_paymentStrategy;public:void addItem(const std::string& item) {m_items.push_back(item);}int calculateTotal() {// 简化计算,假设每件商品10美元return m_items.size() * 10;}void setPaymentStrategy(std::unique_ptr<PaymentStrategy> strategy) {m_paymentStrategy = std::move(strategy);}void checkout() {int amount = calculateTotal();if (m_paymentStrategy) {m_paymentStrategy->pay(amount);std::cout << "Checkout successful! Enjoy your items." << std::endl;} else {std::cout << "Please set a payment method before checkout." << std::endl;}}
};int main() {ShoppingCart cart;cart.addItem("Book");cart.addItem("Laptop");cart.addItem("Mouse");int total = cart.calculateTotal();std::cout << "Total: $" << total << std::endl;// 用户在运行时选择支付策略int choice = 2; // 可以来自用户输入if (choice == 1) {cart.setPaymentStrategy(std::make_unique<CreditCardPayment>("John Doe", "1234-5678-9012-3456"));} else if (choice == 2) {cart.setPaymentStrategy(std::make_unique<PayPalPayment>("john.doe@example.com"));} else if (choice == 3) {cart.setPaymentStrategy(std::make_unique<CryptoPayment>("0xABC123..."));}cart.checkout();return 0;
}

输出

Total: $30
Paid $30 using PayPal (john.doe@example.com)
Checkout successful! Enjoy your items.

:以上内容大部分由DeepSeek生成

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如若转载,请注明出处:http://www.pswp.cn/bicheng/93983.shtml
繁体地址,请注明出处:http://hk.pswp.cn/bicheng/93983.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

在openeuler中如何使用 firewalld 开放指定端口

在 OpenEuler 中使用 firewalld 开放指定端口的操作步骤如下&#xff0c;需区分临时开放&#xff08;重启后失效&#xff09;和永久开放&#xff08;重启后保留&#xff09;两种场景&#xff1a;一、查询端口当前状态首先确认端口是否已开放&#xff0c;避免重复配置&#xff1…

【Java进阶】Java JIT 编译器深度解析与优化实践

Java JIT 编译器深度解析与优化实践Java JIT 编译器深度解析与优化实践一、JIT 编译器核心原理1. JIT 工作流程2. 热点代码检测机制二、Java 8 JIT 优化升级1. 分层编译优化2. 方法内联增强3. 循环优化升级4. 逃逸分析增强5. 向量化支持三、JIT友好代码设计原则1. 方法设计优化…

【本地部署问答软件Apache Answer】Answer开源平台搭建:cpolar内网穿透服务助力全球用户社区构建

文章目录前言1. 本地安装Docker2. 本地部署Apache Answer2.1 设置语言选择简体中文2.2 配置数据库2.3 创建配置文件2.4 填写基本信息3. 如何使用Apache Answer3.1 后台管理3.2 提问与回答3.3 查看主页回答情况4. 公网远程访问本地 Apache Answer4.1 内网穿透工具安装4.2 创建远…

华为数通认证学习

1、华为人才认证官网&#xff0c;https://e.huawei.com/cn/talent/portal/#/ 很全面的网站&#xff0c;包含了概述、了解认证、参加考试、学习资源、认证资讯四个板块。可以了解华为认证的整个流程、下载学习资源&#xff08;培训教材、视频课程等&#xff09;&#xff0c;以及…

Android-ContentProvider的跨应用通信学习总结

一、ContentProvider的概念1. ContentProvider 是什么&#xff1f;&#xff08;核心概念&#xff09;ContentProvider 是 Android 四大组件之一。它的核心职责是管理和共享应用的结构化数据。我们可以把它想象成一个应用的**“数据大使馆”**。在一个国家里&#xff08;Android…

Java数据结构第二十六期:解密位图,海量数据处理的 “空间魔法”

专栏&#xff1a;Java数据结构秘籍 个人主页&#xff1a;手握风云 目录 一、位图 1.1. 概念 1.2. 面试题 1.3. 位图的实现 1.4. 位图的应用 一、位图 1.1. 概念 在数据结构中&#xff0c;位图&#xff08;也称为位数组、位向量或位集&#xff09;是一种紧凑的方式来表示一…

芯科科技即将重磅亮相IOTE 2025深圳物联网展,以全面的无线技术及生态覆盖赋能万物智联

作为低功耗无线连接领域的创新性领导厂商&#xff0c;Silicon Labs&#xff08;亦称“芯科科技”&#xff09;将于8月27至29日携其最前沿的人工智能&#xff08;AI&#xff09;和物联网&#xff08;IoT&#xff09;解决方案在深圳举办的IOTE 2025国际物联网展中盛大展出。这场亚…

Linux上安装多个JDK版本,需要配置环境变量吗

简短回答&#xff1a;不需要同时配置多个 JDK 的 JAVA_HOME 和 PATH&#xff0c;但你可以安装多个版本&#xff0c;并通过灵活的方式在它们之间切换。 文章目录✅ 正确做法&#xff1a;安装多个 JDK&#xff0c;但只让一个生效&#xff08;通过环境变量或 alternatives&#xf…

MySQL有哪些高可用方案

大家好&#xff0c;我是锋哥。今天分享关于【MySQL有哪些高可用方案】面试题。希望对大家有帮助&#xff1b; MySQL有哪些高可用方案? 超硬核AI学习资料&#xff0c;现在永久免费了&#xff01; MySQL 高可用方案是指确保 MySQL 数据库在面对硬件故障、网络故障、负载过重等…

【Windows】Windows平台基于加速地址安装vcpkg并集成到Visual Studio 2017

基础运行环境 启动&#xff1a; 适用于 VS 2017 的 x64 本机工具命令提示 ninja 下载压缩包 https://gh-proxy.com/https:/github.com/ninja-build/ninja/releases/download/v1.13.1/ninja-win.zip 直接解压到c:/Windows (无需配置环境变量) CMake 下载安装包 https://gh-proxy…

LLMs之MCP:Chrome MCP的简介、安装和使用方法、案例应用之详细攻略

LLMs之MCP&#xff1a;Chrome MCP的简介、安装和使用方法、案例应用之详细攻略 目录 Chrome MCP的简介 1、特点 2、与类似项目的比较 Chrome MCP的安装和使用方法 1、安装 2、使用方法 加载 Chrome 扩展 与 MCP 协议客户端一起使用 使用 STDIO 连接&#xff08;替代方…

【Java EE】多线程-初阶 synchronized 关键字 - 监视器锁 monitor lock

synchronized 关键字 - 监视器锁 monitor lock5. synchronized 关键字 - 监视器锁 monitor lock5.1 synchronized 的特性5.2 synchronized 使⽤⽰例5.3 Java 标准库中的线程安全类本节⽬标• 掌握 synchronized关键字5. synchronized 关键字 - 监视器锁 monitor lock &#xf…

Java多线程:从基础到实战

引言多线程是Java并发编程的核心技术之一&#xff0c;广泛应用于服务器开发、数据处理、实时系统等领域。通过多线程&#xff0c;程序可以充分利用CPU资源&#xff0c;提高执行效率&#xff0c;同时处理多个任务。本文将从多线程的基本概念、实现方式、线程状态、同步与通信到常…

list集合可以一边遍历一遍修改元素吗?

今天看来一下Java中list集合部分的八股&#xff0c;发现了一个以前没注意过的问题&#xff0c;记录一下list可以一边遍历一边修改元素吗&#xff1f;答&#xff1a;在 Java 中&#xff0c;List在遍历过程中是否可以修改元素取决于遍历方式和具体的List实现类。①&#xff1a;对…

Infusing fine-grained visual knowledge to Vision-Language Models

Infusing fine-grained visual knowledge to Vision-Language Models Authors: Nikolaos-Antonios Ypsilantis, Kaifeng Chen, Andr Araujo, Ondřej Chum Deep-Dive Summary: 视觉-语言模型中注入细粒度视觉知识 摘要 大规模对比预训练产生了强大的视觉-语言模型&#xf…

RK3576赋能无人机巡检:多路视频+AI识别引领智能化变革

随着工业巡检任务的复杂度不断提升&#xff0c;无人机逐渐取代传统人工&#xff0c;成为电力、能源、林业、农业等行业的“高空作业主力”。然而&#xff0c;巡检并非简单的拍摄和回放&#xff0c;它要求无人机实时采集多路画面、快速分析异常&#xff0c;并稳定回传数据。这对…

ollama Modelfile 文件生成

输入 根据如下TEMPLATE和params写一个modelfile文件&#xff0c;TEMPLATE为&#xff1a;{{- $lastUserIdx : -1 -}} {{- range $idx, $msg : .Messages -}} {{- if eq $msg.Role “user” }}{{ $lastUserIdx $idx }}{{ end -}} {{- end }} {{- if or .System .Tools }}<|i…

关联规则挖掘2:FP-growth算法(Frequent Pattern Growth,频繁模式增长)

目录 一、核心思想&#xff1a;一个形象的比喻 二、核心思想的具体拆解 步骤一&#xff1a;构建FP-tree&#xff08;频繁模式树&#xff09; 步骤二&#xff1a;从FP-tree中挖掘频繁项集 为什么这很高效&#xff1f; 三、总结 核心思想与优势 适用场景与缺点 四、例题…

在IDEA中DEBUG调试时查看MyBatis-Plus动态生成的SQL语句

在IDEA中DEBUG调试时查看MyBatis-Plus动态生成的SQL语句前言&#xff1a;动态SQL调试的痛与解决方案一、准备工作&#xff1a;调试前的检查清单二、基础方法&#xff1a;SqlSessionTemplate断点调试步骤1&#xff1a;定位SqlSessionTemplate类步骤2&#xff1a;在invoke方法上设…

Linux 文本处理三剑客:awk、grep、sed 完全指南

Linux 文本处理三剑客&#xff1a;awk、grep、sed 完全指南 1. 概述 Linux 系统提供了三个强大的文本处理工具&#xff1a;awk、grep 和 sed&#xff0c;它们各有所长&#xff0c;结合使用可以高效地处理文本数据。 awk&#xff1a;擅长文本分析和格式化输出&#xff0c;是一…