C++软件设计模式之状态模式
在C++设计模式中,状态模式(State Pattern)是一种行为设计模式,它允许对象在内部状态改变时改变其行为,使对象看起来似乎修改了其类。状态模式的主要动机、意图和适用场合如下:
动机
在面向对象的设计中,对象的行为往往依赖于其状态。传统的实现方式是在对象中使用大量的条件语句来检查状态并执行相应的操作。这种做法有以下几个问题:
- 代码复杂性:随着状态的增多,条件语句会变得越来越复杂,难以维护。
- 可扩展性差:添加新状态时,需要修改现有的条件语句,违反了开闭原则(对扩展开放,对修改关闭)。
- 状态转移不清晰:状态之间的转移逻辑分散在各个地方,不便于管理和理解。
为了解决这些问题,状态模式应运而生。
意图
状态模式的意图是将对象的状态抽象成类层次结构,并将行为封装在这些状态类中。具体来说:
- 定义一个状态接口,该接口声明了所有可能状态共有的操作。
- 为每种状态实现一个具体的类,每个类都实现了状态接口中的操作,并在必要时处理状态转换。
- 维护一个当前状态的引用,主体对象通过这个引用委托给当前状态对象执行相应的操作。
通过这种方式,状态模式将状态相关的逻辑从主体类中分离出来,使得代码更加清晰、模块化,并且易于扩展。
适用场景
状态模式适用于以下情况:
- 对象行为依赖于其状态,且需要根据状态改变行为。
- 状态之间有复杂的转移逻辑,需要明确地定义状态转换规则。
- 希望将状态相关的代码集中管理,提高代码的可维护性和可扩展性。
- 需要对不同的状态进行不同的操作,并且这些操作可能涉及复杂的业务逻辑。
例如,一个自动售货机可以根据其当前状态(如待支付、已支付、缺货等)执行不同的操作,如接收硬币、发放商品、退还余额等。使用状态模式可以清晰地定义每种状态下的行为以及状态之间的转换。
示例代码
以下是一个简单的C++示例,展示了状态模式的使用:
#include <iostream>
#include <memory>// 状态接口
class State {
public:virtual void handle(const std::string& input) = 0;virtual ~State() = default;
};// 具体状态A
class StateA : public State {
public:void handle(const std::string& input) override {std::cout << "StateA handles: " << input << std::endl;// 可能会转换到其他状态}
};// 具体状态B
class StateB : public State {
public:void handle(const std::string& input) override {std::cout << "StateB handles: " << input << std::endl;// 可能会转换到其他状态}
};// 主体类
class Context {
public:void setState(std::shared_ptr<State> state) {currentState = state;}void request(const std::string& input) {if (currentState) {currentState->handle(input);}}
private:std::shared_ptr<State> currentState;
};int main() {// 创建具体状态实例auto stateA = std::make_shared<StateA>();auto stateB = std::make_shared<StateB>();// 创建上下文并设置初始状态Context context;context.setState(stateA);// 处理请求context.request("Initial request");// 转换状态context.setState(stateB);context.request("Another request");return 0;
}
在这个示例中,Context 类维护了一个 State 接口的指针,并将处理请求委托给当前状态对象。不同的状态类 (StateA 和 StateB) 实现了不同的处理逻辑。通过设置不同的状态,Context 对象可以表现出不同的行为。
通过这种方式,状态模式使得状态相关的逻辑更加清晰和模块化,同时也便于添加新的状态而不需要修改现有的代码。
面是一个使用状态模式来模拟Windows PnP(Plug and Play)设备驱动中状态转移的C++示例。我们将定义一个设备驱动类和多个状态类,每个状态类将处理不同状态下的设备行为和状态转移。
状态模式在PnP设备驱动中的应用
- 定义状态接口:定义一个状态接口
State,声明所有可能状态共有的操作。 - 实现具体状态类:为每种状态(如
Unplugged、PlugIn、Initialize、Ready)实现一个具体的类。 - 维护当前状态:在
DeviceDriver类中维护一个当前状态的引用,并根据需要切换状态。
示例代码
#include <iostream>
#include <memory>
#include <string>// 状态接口
class State {
public:virtual ~State() = default;virtual void onUnplug(DeviceDriver* driver) = 0;virtual void onPlugIn(DeviceDriver* driver) = 0;virtual void onInitialize(DeviceDriver* driver) = 0;virtual void onReady(DeviceDriver* driver) = 0;
};// 设备驱动类
class DeviceDriver {
public:DeviceDriver() : currentState(std::make_shared<Unplugged>()) {}void unplug() {currentState->onUnplug(this);}void plugIn() {currentState->onPlugIn(this);}void initialize() {currentState->onInitialize(this);}void ready() {currentState->onReady(this);}void setState(const std::shared_ptr<State>& state) {currentState = state;}private:std::shared_ptr<State> currentState;
};// 具体状态:未插入
class Unplugged : public State {
public:void onUnplug(DeviceDriver* driver) override {std::cout << "Already unplugged." << std::endl;}void onPlugIn(DeviceDriver* driver) override {std::cout << "Device plugged in." << std::endl;driver->setState(std::make_shared<PlugIn>());}void onInitialize(DeviceDriver* driver) override {std::cout << "Cannot initialize. Device not plugged in." << std::endl;}void onReady(DeviceDriver* driver) override {std::cout << "Cannot be ready. Device not plugged in." << std::endl;}
};// 具体状态:已插入
class PlugIn : public State {
public:void onUnplug(DeviceDriver* driver) override {std::cout << "Device unplugged." << std::endl;driver->setState(std::make_shared<Unplugged>());}void onPlugIn(DeviceDriver* driver) override {std::cout << "Already plugged in." << std::endl;}void onInitialize(DeviceDriver* driver) override {std::cout << "Device initialized." << std::endl;driver->setState(std::make_shared<Initialize>());}void onReady(DeviceDriver* driver) override {std::cout << "Cannot be ready. Device not initialized." << std::endl;}
};// 具体状态:已初始化
class Initialize : public State {
public:void onUnplug(DeviceDriver* driver) override {std::cout << "Device unplugged." << std::endl;driver->setState(std::make_shared<Unplugged>());}void onPlugIn(DeviceDriver* driver) override {std::cout << "Already plugged in and initialized." << std::endl;}void onInitialize(DeviceDriver* driver) override {std::cout << "Already initialized." << std::endl;}void onReady(DeviceDriver* driver) override {std::cout << "Device is ready to use." << std::endl;driver->setState(std::make_shared<Ready>());}
};// 具体状态:已准备好
class Ready : public State {
public:void onUnplug(DeviceDriver* driver) override {std::cout << "Device unplugged." << std::endl;driver->setState(std::make_shared<Unplugged>());}void onPlugIn(DeviceDriver* driver) override {std::cout << "Device is already ready." << std::endl;}void onInitialize(DeviceDriver* driver) override {std::cout << "Device is already initialized and ready." << std::endl;}void onReady(DeviceDriver* driver) override {std::cout << "Device is already ready." << std::endl;}
};int main() {DeviceDriver driver;// 模拟设备插拔和状态转移driver.plugIn();driver.initialize();driver.ready();driver.unplug();driver.plugIn();driver.ready();return 0;
}
代码说明
-
状态接口
State:- 定义了四个虚函数:
onUnplug、onPlugIn、onInitialize、onReady,分别对应设备在不同状态下的行为。
- 定义了四个虚函数:
-
设备驱动类
DeviceDriver:- 维护一个当前状态
currentState,并提供四个公共方法unplug、plugIn、initialize、ready,这些方法委托给当前状态对象处理。 - 提供
setState方法用于切换状态。
- 维护一个当前状态
-
具体状态类:
Unplugged:设备未插入状态。PlugIn:设备已插入状态。Initialize:设备已初始化状态。Ready:设备已准备好状态。
-
主函数
main:- 创建一个
DeviceDriver对象,并模拟设备的插拔和状态转移过程。
- 创建一个
通过这种方式,状态模式使得设备驱动的代码更加模块化和可维护,状态之间的转换也更加清晰
状态模式通常与其他设计模式协同使用,以提高代码的模块化和可维护性。以下是状态模式常见的协同模式及其使用场景:
1. 策略模式 (Strategy Pattern)
- 场景:当不同状态下的行为可以通过不同的算法实现时,可以使用策略模式来定义这些算法。
- 协同方式:状态模式中的每个状态类可以包含一个策略对象,用于实现具体的行为。这样,状态的改变不仅涉及状态的切换,还可以动态改变算法。
- 示例:在状态模式中,不同状态下的设备初始化可以使用不同的初始化策略。
2. 工厂模式 (Factory Pattern)
- 场景:当状态类的创建需要复杂逻辑时,可以使用工厂模式来创建状态对象。
- 协同方式:通过工厂模式,可以在状态切换时动态创建所需的状态对象,而不需要在每个地方重复创建逻辑。
- 示例:使用工厂模式创建设备驱动的初始状态或特定状态。
3. 观察者模式 (Observer Pattern)
- 场景:当状态变化需要通知其他对象时,可以使用观察者模式。
- 协同方式:状态对象可以充当被观察者,其他对象(如日志记录器、UI 更新器等)可以注册为观察者,当状态变化时,观察者会收到通知并作出相应处理。
- 示例:在设备驱动状态变化时,通知UI更新显示状态。
4. 单例模式 (Singleton Pattern)
- 场景:当状态类需要全局唯一实例时,可以使用单例模式。
- 协同方式:状态类可以通过单例模式确保每个状态在整个应用中只有一个实例,这有助于节省资源并确保状态的一致性。
- 示例:确保设备的“未插入”状态在整个应用中只有一个实例。
5. 模板方法模式 (Template Method Pattern)
- 场景:当状态类有共同的骨架方法,但具体实现不同步时,可以使用模板方法模式。
- 协同方式:状态类可以定义一个模板方法,该方法包含一系列步骤,其中某些步骤的具体实现由具体的子类提供。
- 示例:定义一个模板方法
handleEvent,该方法包含一系列步骤,如检查前置条件、执行操作、更新状态等,具体状态类可以覆盖这些步骤的实现。
6. 命令模式 (Command Pattern)
- 场景:当状态变化需要记录或撤销时,可以使用命令模式。
- 协同方式:每个状态变化可以封装成一个命令对象,命令对象可以记录状态变化的操作,便于撤回或重做。
- 示例:记录设备状态变化的命令,以便在需要时恢复到之前的状态。
7. 责任链模式 (Chain of Responsibility Pattern)
- 场景:当状态变化需要多个对象处理时,可以使用责任链模式。
- 协同方式:状态变化可以传递给一个链中的多个对象,每个对象根据其职责处理或传递请求。
- 示例:当设备状态变化时,多个处理器(如日志记录器、安全检查器等)可以顺序处理该状态变化。
示例
以下是一个结合状态模式和工厂模式、策略模式的示例:
#include <iostream>
#include <memory>
#include <string>// 策略接口
class InitializationStrategy {
public:virtual void initialize() = 0;virtual ~InitializationStrategy() = default;
};// 具体策略:快速初始化
class QuickInitialization : public InitializationStrategy {
public:void initialize() override {std::cout << "Quick initialization" << std::endl;}
};// 具体策略:完整初始化
class FullInitialization : public InitializationStrategy {
public:void initialize() override {std::cout << "Full initialization" << std::endl;}
};// 状态接口
class State {
public:virtual ~State() = default;virtual void onUnplug(DeviceDriver* driver) = 0;virtual void onPlugIn(DeviceDriver* driver) = 0;virtual void onInitialize(DeviceDriver* driver) = 0;virtual void onReady(DeviceDriver* driver) = 0;
};// 状态工厂类
class StateFactory {
public:static std::shared_ptr<State> createUnpluggedState() {return std::make_shared<Unplugged>();}static std::shared_ptr<State> createPlugInState() {return std::make_shared<PlugIn>();}static std::shared_ptr<State> createInitializeState() {return std::make_shared<Initialize>();}static std::shared_ptr<State> createReadyState() {return std::make_shared<Ready>();}
};// 设备驱动类
class DeviceDriver {
public:DeviceDriver() : currentState(StateFactory::createUnpluggedState()) {}void unplug() {currentState->onUnplug(this);}void plugIn() {currentState->onPlugIn(this);}void initialize() {currentState->onInitialize(this);}void ready() {currentState->onReady(this);}void setState(const std::shared_ptr<State>& state) {currentState = state;}private:std::shared_ptr<State> currentState;
};// 具体状态:未插入
class Unplugged : public State {
public:void onUnplug(DeviceDriver* driver) override {std::cout << "Already unplugged." << std::endl;}void onPlugIn(DeviceDriver* driver) override {std::cout << "Device plugged in." << std::endl;driver->setState(StateFactory::createPlugInState());}void onInitialize(DeviceDriver* driver) override {std::cout << "Cannot initialize. Device not plugged in." << std::endl;}void onReady(DeviceDriver* driver) override {std::cout << "Cannot be ready. Device not plugged in." << std::endl;}
};// 具体状态:已插入
class PlugIn : public State {
public:PlugIn() : strategy(std::make_unique<QuickInitialization>()) {}void onUnplug(DeviceDriver* driver) override {std::cout << "Device unplugged." << std::endl;driver->setState(StateFactory::createUnpluggedState());}void onPlugIn(DeviceDriver* driver) override {std::cout << "Already plugged in." << std::endl;}void onInitialize(DeviceDriver* driver) override {std::cout << "Device initialized." << std::endl;strategy->initialize();driver->setState(StateFactory::createInitializeState());}void onReady(DeviceDriver* driver) override {std::cout << "Cannot be ready. Device not initialized." << std::endl;}private:std::unique_ptr<InitializationStrategy> strategy;
};// 具体状态:已初始化
class Initialize : public State {
public:void onUnplug(DeviceDriver* driver) override {std::cout << "Device unplugged." << std::endl;driver->setState(StateFactory::createUnpluggedState());}void onPlugIn(DeviceDriver* driver) override {std::cout << "Already plugged in and initialized." << std::endl;}void onInitialize(DeviceDriver* driver) override {std::cout << "Already initialized." << std::endl;}void onReady(DeviceDriver* driver) override {std::cout << "Device is ready to use." << std::endl;driver->setState(StateFactory::createReadyState());}
};// 具体状态:已准备好
class Ready : public State {
public:void onUnplug(DeviceDriver* driver) override {std::cout << "Device unplugged." << std::endl;driver->setState(StateFactory::createUnpluggedState());}void onPlugIn(DeviceDriver* driver) override {std::cout << "Device is already ready." << std::endl;}void onInitialize(DeviceDriver* driver) override {std::cout << "Device is already initialized and ready." << std::endl;}void onReady(DeviceDriver* driver) override {std::cout << "Device is already ready." << std::endl;}
};int main() {DeviceDriver driver;// 模拟设备插拔和状态转移driver.plugIn();driver.initialize();driver.ready();driver.unplug();driver.plugIn();driver.ready();return 0;
}
代码说明
-
策略接口
InitializationStrategy:- 定义了一个初始化策略接口,包含一个
initialize方法。 - 具体策略类
QuickInitialization和FullInitialization实现了不同的初始化策略。
- 定义了一个初始化策略接口,包含一个
-
状态工厂类
StateFactory:- 提供静态方法创建不同状态的实例。
-
具体状态类
PlugIn:- 包含一个策略对象
strategy,在onInitialize方法中使用该策略进行初始化。
- 包含一个策略对象
-
主函数
main:- 创建一个
DeviceDriver对象,并模拟设备的插拔和状态转移过程。
- 创建一个
通过这种方式,状态模式与工厂模式和策略模式协同使用,使得代码更加灵活和可维护。
相关文章:
C++软件设计模式之状态模式
在C设计模式中,状态模式(State Pattern)是一种行为设计模式,它允许对象在内部状态改变时改变其行为,使对象看起来似乎修改了其类。状态模式的主要动机、意图和适用场合如下: 动机 在面向对象的设计中&…...
Microsoft Visual Studio中的/MT, /MTd,/MD,/MDd分别是什么意思?
1. /MT,/MTd,/MD,/MDd的含义 /MT,/MTd,/MD,/MDd是 Microsoft Visual C 编译器的运行时库链接选项。它们决定了程序如何链接 C 运行时库(CRT)。具体含义如下: /MT&#x…...
谷粒商城项目125-spring整合high-level-client
新年快乐! 致2025年还在努力学习的你! 你已经很努力了,今晚就让自己好好休息一晚吧! 在后端中选用哪种elasticsearch客户端? elasticsearch可以通过9200或者9300端口进行操作 1)9300:TCP spring-data-elasticsearch:transport-…...
日期时间选择(设置禁用状态)
目录 1.element文档需要 2.禁用所有过去的时间 3.设置指定日期的禁用时间 <template><div class"block"><span class"demonstration">起始日期时刻为 12:00:00</span><el-date-pickerv-model"value1"type"dat…...
基于SpringBoot的题库管理系统的设计与实现(源码+SQL+LW+部署讲解)
文章目录 摘 要1. 第1章 选题背景及研究意义1.1 选题背景1.2 研究意义1.3 论文结构安排 2. 第2章 相关开发技术2.1 前端技术2.2 后端技术2.3 数据库技术 3. 第3章 可行性及需求分析3.1 可行性分析3.2 系统需求分析 4. 第4章 系统概要设计4.1 系统功能模块设计4.2 数据库设计 5.…...
钉钉h5微应用安卓报错error29 ios报错error3 加上报错52013,签名校验失败 (前端)
这两个都是应为 免登报错52013,签名校验失败 用户后端签名使用的url地址和前端访问地址需要严格一致,包括端口号。前端部分可以用alert显示出当前的location.href,后端部分请在签名的时候打印日志。 访问通过反向代理服务器、各种NAT等场景下…...
Vue.js组件开发-客户端如何限制刷新Token次数
在Vue.js组件开发中,限制刷新Token的次数是一个重要的安全措施,可以防止恶意用户或攻击者无限次尝试刷新Token。 客户端限制 在客户端,可以通过Vuex、localStorage或sessionStorage等存储机制来跟踪刷新Token的尝试次数。以下是一个基本的实…...
Linux上安装jdk
在线环境的话,通过命令下载,离线环境的话,组要自行去oracle官网下载后上传 wget --no-check-certificate --no-cookies --header "Cookie: oraclelicenseaccept-securebackup-cookie" http://download.oracle.com/otn-pub/java/jd…...
Ardunio BLE keyboard 库的使用
为了开发一个 ardunio 的蓝牙选歌器,网络上普遍推荐使用: https://github.com/T-vK/ESP32-BLE-Keyboard 结果搞了好几天,就是不行。最后发现,下面两点非常重要: 使用 NimBle-ardunio 库这个库目前是2.1.2 ÿ…...
django --递归查询评论
表数据 树状结构 action(methods(GET, ), detailFalse) def get_info_pinglun(self, request, *args, **kwargs) -> Response:根据评论id查所有回复params wenxian_pinglun_id --> 评论id;wenxian_pinglun_id self.request.GET.get(wenxian_pinglun_id)results se…...
【开源免费】基于SpringBoot+Vue.JS音乐网站(JAVA毕业设计)
本文项目编号 T 109 ,文末自助获取源码 \color{red}{T109,文末自助获取源码} T109,文末自助获取源码 目录 一、系统介绍二、数据库设计三、配套教程3.1 启动教程3.2 讲解视频3.3 二次开发教程 四、功能截图五、文案资料5.1 选题背景5.2 国内…...
SUBSTRING_INDEX()在MySQL中的用法
语法: SUBSTRING_INDEX() 是 MySQL 中的一个字符串函数,它返回一个字符串,该字符串包含从字符串的开始或结束到指定的子字符串出现指定次数为止的部分。这个函数的语法如下: SUBSTRING_INDEX(string, delimiter, count)string&a…...
对45家“AI+安全”产品/方案的分析
一. 关键洞察 “AI+安全”创新非常活跃,一片百家争鸣之势,赛道选择上,以事件分诊Incident Triage、 安全辅助Security Copilots、自动化Automation三者为主为主,这充分反映了当前安全运营的主要需求,在产品理念选择上以 AI 和 自动化为主,这确实又切合上了在关键…...
Oracle Dataguard(主库为 Oracle 11g 单节点)配置详解(1):Oracle Dataguard 概述
Oracle Dataguard(主库为 Oracle 11g 单节点)配置详解(1):Oracle Dataguard 概述 目录 Oracle Dataguard(主库为 Oracle 11g 单节点)配置详解(1):Oracle Data…...
Pycharm 中 virtualenv、pipenv、conda 虚拟环境的用法
文章目录 前言虚拟环境的通俗介绍虚拟环境和非虚拟环境该怎么选?通过 Virtualenv 方式创建虚拟环境通过 Pipenv 方式创建虚拟环境通过 Conda 方式创建虚拟环境前言 在网上找了好一些资料,发现介绍 Pycharm 虚拟环境的不多,查了一些资料,并做个总结。 本文主要是介绍 Pycha…...
UNI-APP弹窗
组件代码 <template><view><!-- 蒙版 --><view class"mask" click"close()" v-show"tanchuang"></view><!-- 弹窗 --><view class"pop" :style"{height:height*0.8 px,top:tanchuang?…...
【大模型实战篇】LLaMA Factory微调ChatGLM-4-9B模型
1. 背景介绍 虽然现在大模型微调的文章很多,但纸上得来终觉浅,大模型微调的体感还是需要自己亲自上手实操过,才能有一些自己的感悟和直觉。这次我们选择使用llama_factory来微调chatglm-4-9B大模型。 之前微调我们是用两块3090GPU显卡&…...
【Cesium】三、实现开场动画效果
文章目录 实现效果实现方法实现代码组件化 实现效果 实现方法 Cesium官方提供了Camera的flyTo方法实现了飞向目的地的动画效果。 官方API:传送门 这里只需要用到目的地(destination)和持续时间(duration)这两个参数…...
#渗透测试#红蓝攻防#红队打点web服务突破口总结01
免责声明 本教程仅为合法的教学目的而准备,严禁用于任何形式的违法犯罪活动及其他商业行为,在使用本教程前,您应确保该行为符合当地的法律法规,继续阅读即表示您需自行承担所有操作的后果,如有异议,请立即停…...
适用于项目经理的跨团队协作实践:Atlassian Jira与Confluence集成
适用于项目经理的跨团队协作实践:Atlassian Jira与Confluence集成 现代项目经理的核心职责是提供可视性、保持团队一致,并确保团队拥有交付出色工作所需的资源。在过去几年中,由于分布式团队的需求不断增加,项目经理这一角色已迅速…...
日语AI面试高效通关秘籍:专业解读与青柚面试智能助攻
在如今就业市场竞争日益激烈的背景下,越来越多的求职者将目光投向了日本及中日双语岗位。但是,一场日语面试往往让许多人感到步履维艰。你是否也曾因为面试官抛出的“刁钻问题”而心生畏惧?面对生疏的日语交流环境,即便提前恶补了…...
大型活动交通拥堵治理的视觉算法应用
大型活动下智慧交通的视觉分析应用 一、背景与挑战 大型活动(如演唱会、马拉松赛事、高考中考等)期间,城市交通面临瞬时人流车流激增、传统摄像头模糊、交通拥堵识别滞后等问题。以演唱会为例,暖城商圈曾因观众集中离场导致周边…...
基于Flask实现的医疗保险欺诈识别监测模型
基于Flask实现的医疗保险欺诈识别监测模型 项目截图 项目简介 社会医疗保险是国家通过立法形式强制实施,由雇主和个人按一定比例缴纳保险费,建立社会医疗保险基金,支付雇员医疗费用的一种医疗保险制度, 它是促进社会文明和进步的…...
前端导出带有合并单元格的列表
// 导出async function exportExcel(fileName "共识调整.xlsx") {// 所有数据const exportData await getAllMainData();// 表头内容let fitstTitleList [];const secondTitleList [];allColumns.value.forEach(column > {if (!column.children) {fitstTitleL…...
质量体系的重要
质量体系是为确保产品、服务或过程质量满足规定要求,由相互关联的要素构成的有机整体。其核心内容可归纳为以下五个方面: 🏛️ 一、组织架构与职责 质量体系明确组织内各部门、岗位的职责与权限,形成层级清晰的管理网络…...
ESP32 I2S音频总线学习笔记(四): INMP441采集音频并实时播放
简介 前面两期文章我们介绍了I2S的读取和写入,一个是通过INMP441麦克风模块采集音频,一个是通过PCM5102A模块播放音频,那如果我们将两者结合起来,将麦克风采集到的音频通过PCM5102A播放,是不是就可以做一个扩音器了呢…...
select、poll、epoll 与 Reactor 模式
在高并发网络编程领域,高效处理大量连接和 I/O 事件是系统性能的关键。select、poll、epoll 作为 I/O 多路复用技术的代表,以及基于它们实现的 Reactor 模式,为开发者提供了强大的工具。本文将深入探讨这些技术的底层原理、优缺点。 一、I…...
ABAP设计模式之---“简单设计原则(Simple Design)”
“Simple Design”(简单设计)是软件开发中的一个重要理念,倡导以最简单的方式实现软件功能,以确保代码清晰易懂、易维护,并在项目需求变化时能够快速适应。 其核心目标是避免复杂和过度设计,遵循“让事情保…...
听写流程自动化实践,轻量级教育辅助
随着智能教育工具的发展,越来越多的传统学习方式正在被数字化、自动化所优化。听写作为语文、英语等学科中重要的基础训练形式,也迎来了更高效的解决方案。 这是一款轻量但功能强大的听写辅助工具。它是基于本地词库与可选在线语音引擎构建,…...
Angular微前端架构:Module Federation + ngx-build-plus (Webpack)
以下是一个完整的 Angular 微前端示例,其中使用的是 Module Federation 和 npx-build-plus 实现了主应用(Shell)与子应用(Remote)的集成。 🛠️ 项目结构 angular-mf/ ├── shell-app/ # 主应用&…...
