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

设计模式(1)

23种设计模式大概分为三大类:

5种(创建型模式):工厂方法模式、抽象工厂模式、单例模式、原型模式、建造者模式。

7种(结构型模式):适配器模式、装饰器模式、代理模式、外观模式、桥接模式、组合模式、享元模式。

11种(行为型模式):策略模式、模板方法模式、观察者模式、迭代器模式、责任链模式、命令模式、备忘录模式、状态模式、访问者模式、中介者模式、解释器模式。

行为型又可以通过类与类之间的关系进行划分 :

一、策略模式

1.讲解

策略(Strategy)模式的定义:该模式定义了一系列算法,并将每个算法封装起来,使它们可以相互替换,且算法的变化不会影响使用算法的客户。策略模式属于对象行为模式,它通过对算法进行封装,把使用算法的责任和算法的实现分割开来,并委派给不同的对象对这些算法进行管理。

策略模式有三个组成角色:
抽象策略(Strategy)类
具体策略(Concrete Strategy)类
环境(Context)类

这三个角色贯穿策略模式的整个设计思想。

核心思想

  • 封装变化的部分(算法、逻辑)

  • 对外暴露统一的接口

  • 运行时可以自由切换算法

+-------------------+
|   Strategy         |  <-- 抽象策略接口
| + execute()        |
+-------------------+▲|
+-------------------+    +-------------------+
| ConcreteStrategyA |    | ConcreteStrategyB |
| + execute()       |    | + execute()       |
+-------------------+    +-------------------+▲|
+-------------------+
|   Context         |
| - strategy: ptr   |
| + setStrategy()   |
| + execute()       |
+-------------------+

2.示例场景

由于现在大部分用的C语言,所以这里就以C语言来模拟。

C 没有类和继承,我们可以用 函数指针 + 结构体 来模拟接口和多态。

假设有一个支付系统,支持多种支付方式(现金、信用卡、支付宝)。不同支付方式是策略模式中的策略,统一的支付接口是策略模式中的抽象策略

#include <stdio.h>
#include <stdlib.h>/* 抽象策略接口 */
typedef struct PaymentStrategy {void (*pay)(struct PaymentStrategy *self, double amount);
} PaymentStrategy;/* 具体策略:现金支付 */
typedef struct {PaymentStrategy base;
} CashPayment;void cash_pay(PaymentStrategy *self, double amount) {printf("使用现金支付 %.2f 元\n", amount);
}/* 具体策略:信用卡支付 */
typedef struct {PaymentStrategy base;const char *card_number;
} CreditCardPayment;void credit_card_pay(PaymentStrategy *self, double amount) {CreditCardPayment *cc = (CreditCardPayment *)self;printf("使用信用卡 %s 支付 %.2f 元\n", cc->card_number, amount);
}/* 具体策略:支付宝支付 */
typedef struct {PaymentStrategy base;const char *account;
} AlipayPayment;void alipay_pay(PaymentStrategy *self, double amount) {AlipayPayment *ap = (AlipayPayment *)self;printf("使用支付宝账户 %s 支付 %.2f 元\n", ap->account, amount);
}/* Context 上下文 */
typedef struct {PaymentStrategy *strategy;
} PaymentContext;void set_strategy(PaymentContext *context, PaymentStrategy *strategy) {context->strategy = strategy;
}void execute_payment(PaymentContext *context, double amount) {if (context->strategy && context->strategy->pay) {context->strategy->pay(context->strategy, amount);} else {printf("未设置支付策略!\n");}
}/* 测试 */
int main(void) {PaymentContext context;/* 创建现金支付策略 */CashPayment cash = { { cash_pay } };/* 创建信用卡支付策略 */CreditCardPayment cc = { { credit_card_pay }, "1234-5678-9876-5432" };/* 创建支付宝支付策略 */AlipayPayment ap = { { alipay_pay }, "user@example.com" };/* 使用现金支付 */set_strategy(&context, (PaymentStrategy *)&cash);execute_payment(&context, 100.0);/* 切换为信用卡支付 */set_strategy(&context, (PaymentStrategy *)&cc);execute_payment(&context, 250.0);/* 切换为支付宝支付 */set_strategy(&context, (PaymentStrategy *)&ap);execute_payment(&context, 88.8);return 0;
}
  • 函数指针实现多态
    在 C 里没有虚函数,但我们用函数指针模拟“接口”。

  • 上下文持有策略指针
    PaymentContext 不直接实现支付逻辑,只调用当前策略的 pay

  • 运行时可替换策略
    set_strategy 可以动态切换不同策略,符合策略模式“可替换算法”的特性。

  • 封装变化
    新增一种支付方式时,只需实现一个新的策略结构体和对应的函数,不需要改 PaymentContext

3.在RT_Thread中的应用
优点缺点
多重条件语句不易维护,而使用策略模式可以避免使用多重条件语句,如 if…else 语句、switch…case 语句。客户端必须理解所有策略算法的区别,以便适时选择恰当的算法类。
策略模式提供了一系列的可供重用的算法族,恰当使用继承可以把算法族的公共代码转移到父类里面,从而避免重复的代码策略模式造成很多的策略类,增加维护难度。

以上这两种方式在RT-Thread里有表现。

第一个优点的表现就是在object的对象管理中,用数组与链表来维护,根据对象的type和name进行索引,而不是if else。

第二个点的变现就是设备驱动的 ops 函数表,例如 struct rt_device_opsstruct rt_pin_opsstruct rt_spi_ops。把具体硬件的实现(不同厂商的驱动)封装成不同的“策略”,在运行时通过函数指针调用,不需要上层关心底层具体实现。

struct rt_pin_ops {void (*pin_mode)(rt_device_t dev, rt_base_t pin, rt_base_t mode);void (*pin_write)(rt_device_t dev, rt_base_t pin, rt_base_t value);int  (*pin_read)(rt_device_t dev, rt_base_t pin);
};

不同的 PIN 驱动只要填好这些函数指针,上层 rt_pin_mode() 调用的就是对应的实现。
这就是策略模式

二、模板方法模式

1.讲解

模板方法模式(Template Method Pattern),又叫模板模式(Template Pattern),在一个抽象类公开定义了执行它的方法的模板。它的子类可以按需要重写方法实现,但调用将以抽象类中定义的方式进行。
简单说,模板方法模式,定义一个操作中的算法的骨架,而将一些步骤延迟到子类中,使得子类可以不改变一个算法的结构,就可以重定义该算法的某些特定步骤,这种类型的设计模式属于行为型模式。

对原理类图的说明:

AbstractClass 抽象类, 类中实现了模板方法(template),定义了算法的骨架,具体子类需要去实现 其它的抽象方法 operation2,3,4。
ConcreteClass 实现抽象方法,假设是operation2,3,4, 以完成算法中特定子类的具体业务步骤。

+-------------------+
| AbstractClass      |
| + templateMethod() |  <-- 模板方法:固定算法步骤
| + step1()          |  <-- 抽象步骤
| + step2()          |
+-------------------+▲|
+-------------------+
| ConcreteClassA     |  <-- 实现步骤1和步骤2
| + step1()          |
| + step2()          |
+-------------------+
+-------------------+
| ConcreteClassB     |  <-- 实现步骤1和步骤2
| + step1()          |
| + step2()          |
+-------------------+

基本思想是:算法只存在于一个地方,也就是在父类中,容易修改。需要修改算法时,只要修改父类的模板方法或者已经实现的某些步骤,子类就会继承这些修改。

  • 固定算法流程(骨架不变)

  • 部分步骤由子类(或具体实现)提供

优点与缺点:

①实现了最大化代码复用。父类的模板方法和已实现的某些步骤会被子类继承而直接使用;
②既统一了算法,也提供了很大的灵活性。父类的模板方法确保了算法的结构保持不变,同时由子类提供部分步骤的实现。让子类只关注可变部分。
③该模式的不足之处:每一个不同的实现都需要一个子类实现,导致类的个数增加,使得系统更加庞大。

④扩展新的流程步骤时,可能需要修改抽象类(影响已有子类)

模板方法模式使用场景:

①当要完成在某个过程,该过程要执行一系列步骤 ,这一系列的步骤基本相同,但其个别步骤在实现时可能不同,通常考虑用模板方法模式来处理。

②统计某一段代码的执行时间也可以用模板方法模式:在前面打印出代码执行前的时间,后面再打印出代码执行后的时间,中间部分就是不同的执行代码。

2.示例

C 没有类和继承,我们可以用 结构体 + 函数指针 来模拟:

  • “父类”就是一个结构体,里面有:

    • 模板方法(固定流程)

    • 一些函数指针,留给“子类”实现

  • “子类”就是具体实现这些函数指针的结构体实例

做一个“泡饮料”程序:

  • 固定流程(模板方法):

    1. 烧水

    2. 冲泡

    3. 倒入杯中

    4. 添加调料

  • 冲泡添加调料 是不同饮料的差异化步骤:

    • 泡茶

    • 泡咖啡

#include <stdio.h>
#include <stdlib.h>/* 抽象父类:饮料制作流程 */
typedef struct Beverage {void (*brew)(struct Beverage *self);      // 冲泡(子类实现)void (*add_condiments)(struct Beverage *self); // 添加调料(子类实现)
} Beverage;/* 模板方法:固定流程 */
void prepare_recipe(Beverage *self) {printf("1. 烧开水\n");if (self->brew) self->brew(self);printf("3. 把饮料倒入杯中\n");if (self->add_condiments) self->add_condiments(self);
}/* ------------------ 具体子类:茶 ------------------ */
typedef struct {Beverage base;
} Tea;void tea_brew(Beverage *self) {printf("2. 泡茶叶\n");
}void tea_add_condiments(Beverage *self) {printf("4. 加柠檬\n");
}Tea *create_tea() {Tea *t = malloc(sizeof(Tea));t->base.brew = tea_brew;t->base.add_condiments = tea_add_condiments;return t;
}/* ------------------ 具体子类:咖啡 ------------------ */
typedef struct {Beverage base;
} Coffee;void coffee_brew(Beverage *self) {printf("2. 冲咖啡粉\n");
}void coffee_add_condiments(Beverage *self) {printf("4. 加糖和牛奶\n");
}Coffee *create_coffee() {Coffee *c = malloc(sizeof(Coffee));c->base.brew = coffee_brew;c->base.add_condiments = coffee_add_condiments;return c;
}/* ------------------ 测试 ------------------ */
int main(void) {Tea *tea = create_tea();Coffee *coffee = create_coffee();printf("=== 制作茶 ===\n");prepare_recipe((Beverage *)tea);printf("\n=== 制作咖啡 ===\n");prepare_recipe((Beverage *)coffee);free(tea);free(coffee);return 0;
}

3.在RT_Thread中的应用

出现在rt_device_open()rt_device_read()rt_device_control() 等通用管理接口。在公共代码里写好执行流程,某些步骤(如 device_open())延迟到具体驱动去实现。

rt_device_open(dev, oflag):1. 检查标志位2. 判断设备状态3. 如果驱动有自己的 open 回调 → 调用它4. 否则用默认逻辑

框架控制流程,驱动只重写自己需要的部分,就是典型模板方法模式

三、工厂模式

1.讲解

(4 封私信) 设计模式篇——工厂模式详解 - 知乎

工厂模式的作用可以用一句话概括:把“创建对象”的逻辑从“使用对象”的代码中分离出来,从而让创建过程更灵活、更可扩展。把对象的创建封装起来,让使用者只管用、不关心怎么造,从而解耦、易扩展、方便维护。

核心作用

  1. 解耦

    使用对象的代码(业务逻辑)不依赖具体类的构造细节,只依赖一个统一的接口/抽象类型。这样,即使对象的具体实现变化了,调用方也不用改。
  2. 可扩展

    新增产品种类时,只需要增加一个具体工厂(或修改工厂方法),而不必改业务逻辑。对应“开闭原则”(对扩展开放,对修改封闭)。
  3. 集中管理对象创建

    • 统一管理对象的构造过程,方便维护,比如:

      统一设置默认值;控制对象数量(缓存/单例);处理资源分配;封装复杂初始化逻辑;
  4. 隐藏创建细节

    调用方不关心是 mallocstrdupnew,还是从对象池里取——工厂统一屏蔽细节。

生活类比

  • 去买饮料时,你只告诉售货员“我要可乐”,你不需要知道瓶子怎么灌、标签怎么贴。

  • 售货员就是工厂,他根据你要的类型返回对应的产品,你拿来直接用。


在不同版本中的作用差异

  • 简单工厂:集中管理一个地方创建所有对象,调用方便,但扩展时可能要改工厂代码。

  • 工厂方法:把创建某种产品的权力交给子类(具体工厂),新增产品无需改原代码。

  • 抽象工厂:一次创建一族相关产品(例如 Win 风格的 Button + Checkbox),确保风格/平台一致。


在 C 中的好处

虽然 C 没有面向对象的类和继承,但工厂模式在 C 中依然有用:

  • 隐藏 malloc 和结构体初始化细节

  • 返回多态对象(通过函数指针)

  • 便于替换模块实现(平台移植、驱动切换等)

以简单工厂模式来举一个简单的例子

typedef struct {void (*speak)(void);
} Animal;void dog_speak(void) { printf("Woof!\n"); }
void cat_speak(void) { printf("Meow!\n"); }Animal* create_animal(const char* type) {Animal *a = malloc(sizeof(Animal));if (strcmp(type, "dog") == 0) a->speak = dog_speak;else if (strcmp(type, "cat") == 0) a->speak = cat_speak;return a;
}int main(void) {Animal *a = create_animal("dog");a->speak();free(a);
}

调用方不需要知道 Animal 是怎么构造的,也不用管函数指针怎么设置。

下图为一张 “有工厂 vs 没工厂” 的代码耦合度对比图,一眼看到区别。

①没有工厂模式

┌───────────────┐
│ 业务代码       │
│               │
│ a = malloc(...)      ← 必须知道用什么结构体
│ a->func = xxx;       ← 必须手动初始化
│ a->param = ...;      ← 必须知道内部细节
│ ...                  ← 变化时业务代码全得改
└───────────────┘

缺点

  • 业务代码必须知道具体产品类型(结构体名、字段、初始化细节)

  • 如果产品结构变了,所有用它的地方都要改

  • 新增另一种产品时,业务代码也得加判断和初始化逻辑 → 扩展性差

②有工厂模式

┌───────────────┐       ┌─────────────┐
│ 业务代码       │       │ 工厂        │
│               │       │ create_xxx │
│ a = factory_create("dog"); ───────►│ { 内部决定用什么结构 }
│ a->func();    │       │ 初始化字段 │
│               │       │ 返回对象   │
└───────────────┘       └─────────────┘

优点

  • 业务代码只调用 factory_create(),不用关心内部细节

  • 产品结构、初始化逻辑的变化 只影响工厂,不影响业务代码

  • 新增产品只需在工厂中增加分支(简单工厂)或新增具体工厂类(工厂方法/抽象工厂)

对比点没有工厂有工厂模式
创建逻辑位置分散在业务代码中集中在工厂里
业务与产品耦合度高(直接依赖结构细节)低(只依赖接口/工厂)
修改成本
扩展新产品需要改业务代码不改业务,只扩展工厂

下面讲一下:工厂方法模式与抽象工厂模式。 这两个与简单工厂的区别在于简单工厂模式在添加新产品时需要在工厂中增加分支;而后两种则又抽象出一个接口,可以直接增加抽象类即可,不影响父类。

2.示例场景

用**同一场景(跨平台 UI 控件)**给出两套 C 语言实现:

  • 工厂方法:只生产一种产品(Button)。把“创建单个产品的细节”下放给子类工厂;新增产品种类时扩展子类工厂即可。

  • 抽象工厂:生产一族相关产品(Button + Checkbox),且保证它们属于同一平台(Windows / macOS)的一致性。提供“创建一族相关产品”的一整套工厂接口;确保同一族产品(如 Win 风格按钮 + 复选框)一起创建、风格一致。

使用时机:

  • 只关心某一种产品(例如只有 Button),但会有不同变体(WinButton / MacButton)→ 工厂方法。

  • 要成套创建多个相关产品(Button + Checkbox + …),并保证平台/主题一致 → 抽象工厂。

公共产品接口(供两种模式共用)

#include <stdio.h>
#include <stdlib.h>
#include <string.h>/* ========== 通用:Button 产品接口 ========== */
typedef struct Button Button;
struct Button {void (*render)(Button *self);void (*click)(Button *self);void (*destroy)(Button *self);
};/* WinButton 具体产品 */
typedef struct {Button base;char  *title;
} WinButton;static void win_button_render(Button *self) {WinButton *b = (WinButton*)self;printf("[Win] Render Button: %s\n", b->title);
}
static void win_button_click(Button *self) {WinButton *b = (WinButton*)self;printf("[Win] Click Button: %s\n", b->title);
}
static void win_button_destroy(Button *self) {WinButton *b = (WinButton*)self;free(b->title);free(b);
}
static Button* create_win_button(const char *title) {WinButton *b = (WinButton*)malloc(sizeof(*b));b->base.render  = win_button_render;b->base.click   = win_button_click;b->base.destroy = win_button_destroy;b->title = strdup(title);return (Button*)b;
}/* MacButton 具体产品 */
typedef struct {Button base;char  *title;
} MacButton;static void mac_button_render(Button *self) {MacButton *b = (MacButton*)self;printf("[Mac] Render Button: %s\n", b->title);
}
static void mac_button_click(Button *self) {MacButton *b = (MacButton*)self;printf("[Mac] Click Button: %s\n", b->title);
}
static void mac_button_destroy(Button *self) {MacButton *b = (MacButton*)self;free(b->title);free(b);
}
static Button* create_mac_button(const char *title) {MacButton *b = (MacButton*)malloc(sizeof(*b));b->base.render  = mac_button_render;b->base.click   = mac_button_click;b->base.destroy = mac_button_destroy;b->title = strdup(title);return (Button*)b;
}

工厂方法模式:只生产「Button」

  • 定义一个抽象工厂接口:create_button()

  • 每个具体工厂(Win/Mac)只负责一种产品的创建(Button),返回多态的 Button*

/* ========== 工厂方法:Button 工厂接口 ========== */
typedef struct ButtonFactory ButtonFactory;
struct ButtonFactory {Button* (*create_button)(ButtonFactory *self, const char *title);
};/* Win 平台的具体 Button 工厂 */
typedef struct {ButtonFactory base;/* 可扩展放平台配置字段 */
} WinButtonFactory;static Button* win_factory_create_button(ButtonFactory *self, const char *title) {(void)self;return create_win_button(title);
}
static void init_win_button_factory(WinButtonFactory *f) {f->base.create_button = win_factory_create_button;
}/* Mac 平台的具体 Button 工厂 */
typedef struct {ButtonFactory base;
} MacButtonFactory;static Button* mac_factory_create_button(ButtonFactory *self, const char *title) {(void)self;return create_mac_button(title);
}
static void init_mac_button_factory(MacButtonFactory *f) {f->base.create_button = mac_factory_create_button;
}/* ========== 演示:工厂方法 ========== */
static void demo_factory_method(void) {printf("=== Factory Method Demo (Button only) ===\n");WinButtonFactory wbf; init_win_button_factory(&wbf);MacButtonFactory mbf; init_mac_button_factory(&mbf);Button *btn1 = wbf.base.create_button((ButtonFactory*)&wbf, "OK");Button *btn2 = mbf.base.create_button((ButtonFactory*)&mbf, "Cancel");btn1->render(btn1); btn1->click(btn1);btn2->render(btn2); btn2->click(btn2);btn1->destroy(btn1);btn2->destroy(btn2);
}

优点

  • 新增按钮的变体(比如 LinuxButton)→ 新增一个工厂类即可。
    局限

  • 只能处理一种产品(Button)。需要 Checkbox 时就得再建一套工厂接口或转为抽象工厂。

抽象工厂模式:生产一族产品(Button + Checkbox)

  • 定义多个产品接口(Button、Checkbox)。

  • 定义抽象工厂能一次创建这一族相关产品(create_button + create_checkbox)。

  • 不同具体工厂(Win/Mac)产出彼此兼容的产品族。

/* ========== 新增产品接口:Checkbox ========== */
typedef struct Checkbox Checkbox;
struct Checkbox {void (*render)(Checkbox *self);void (*toggle)(Checkbox *self, int checked);void (*destroy)(Checkbox *self);int   checked;
};/* WinCheckbox */
typedef struct {Checkbox base;char *label;
} WinCheckbox;static void win_checkbox_render(Checkbox *self) {WinCheckbox *c = (WinCheckbox*)self;printf("[Win] Render Checkbox: %s (checked=%d)\n", c->label, self->checked);
}
static void win_checkbox_toggle(Checkbox *self, int checked) {self->checked = checked;printf("[Win] Toggle Checkbox -> %d\n", checked);
}
static void win_checkbox_destroy(Checkbox *self) {WinCheckbox *c = (WinCheckbox*)self;free(c->label);free(c);
}
static Checkbox* create_win_checkbox(const char *label) {WinCheckbox *c = (WinCheckbox*)malloc(sizeof(*c));c->base.render  = win_checkbox_render;c->base.toggle  = win_checkbox_toggle;c->base.destroy = win_checkbox_destroy;c->base.checked = 0;c->label = strdup(label);return (Checkbox*)c;
}/* MacCheckbox */
typedef struct {Checkbox base;char *label;
} MacCheckbox;static void mac_checkbox_render(Checkbox *self) {MacCheckbox *c = (MacCheckbox*)self;printf("[Mac] Render Checkbox: %s (checked=%d)\n", c->label, self->checked);
}
static void mac_checkbox_toggle(Checkbox *self, int checked) {self->checked = checked;printf("[Mac] Toggle Checkbox -> %d\n", checked);
}
static void mac_checkbox_destroy(Checkbox *self) {MacCheckbox *c = (MacCheckbox*)self;free(c->label);free(c);
}
static Checkbox* create_mac_checkbox(const char *label) {MacCheckbox *c = (MacCheckbox*)malloc(sizeof(*c));c->base.render  = mac_checkbox_render;c->base.toggle  = mac_checkbox_toggle;c->base.destroy = mac_checkbox_destroy;c->base.checked = 0;c->label = strdup(label);return (Checkbox*)c;
}/* ========== 抽象工厂:平台工厂,创建“同一族产品” ========== */
typedef struct PlatformFactory PlatformFactory;
struct PlatformFactory {Button*   (*create_button)(PlatformFactory *self, const char *title);Checkbox* (*create_checkbox)(PlatformFactory *self, const char *label);
};/* Win 平台的具体工厂(产出 Win 风格 Button + Checkbox) */
typedef struct {PlatformFactory base;
} WinPlatformFactory;static Button*   win_pf_create_button(PlatformFactory *self, const char *title) {(void)self; return create_win_button(title);
}
static Checkbox* win_pf_create_checkbox(PlatformFactory *self, const char *label) {(void)self; return create_win_checkbox(label);
}
static void init_win_platform_factory(WinPlatformFactory *f) {f->base.create_button   = win_pf_create_button;f->base.create_checkbox = win_pf_create_checkbox;
}/* Mac 平台的具体工厂(产出 Mac 风格 Button + Checkbox) */
typedef struct {PlatformFactory base;
} MacPlatformFactory;static Button*   mac_pf_create_button(PlatformFactory *self, const char *title) {(void)self; return create_mac_button(title);
}
static Checkbox* mac_pf_create_checkbox(PlatformFactory *self, const char *label) {(void)self; return create_mac_checkbox(label);
}
static void init_mac_platform_factory(MacPlatformFactory *f) {f->base.create_button   = mac_pf_create_button;f->base.create_checkbox = mac_pf_create_checkbox;
}/* ========== 演示:抽象工厂 ========== */
static void render_login_dialog(PlatformFactory *pf) {Button   *ok     = pf->create_button(pf, "OK");Button   *cancel = pf->create_button(pf, "Cancel");Checkbox *remember = pf->create_checkbox(pf, "Remember me");ok->render(ok);      cancel->render(cancel);remember->render(remember);ok->click(ok);remember->toggle(remember, 1);remember->render(remember);ok->destroy(ok);cancel->destroy(cancel);remember->destroy(remember);
}static void demo_abstract_factory(void) {printf("\n=== Abstract Factory Demo (Button + Checkbox family) ===\n");WinPlatformFactory wpf; init_win_platform_factory(&wpf);MacPlatformFactory mpf; init_mac_platform_factory(&mpf);printf("-- Render on Windows theme --\n");render_login_dialog((PlatformFactory*)&wpf);printf("\n-- Render on macOS theme --\n");render_login_dialog((PlatformFactory*)&mpf);
}

结果

int main(void) {demo_factory_method();demo_abstract_factory();return 0;
}
=== Factory Method Demo (Button only) ===
[Win] Render Button: OK
[Win] Click Button: OK
[Mac] Render Button: Cancel
[Mac] Click Button: Cancel=== Abstract Factory Demo (Button + Checkbox family) ===
-- Render on Windows theme --
[Win] Render Button: OK
[Win] Render Button: Cancel
[Win] Render Checkbox: Remember me (checked=0)
[Win] Click Button: OK
[Win] Toggle Checkbox -> 1
[Win] Render Checkbox: Remember me (checked=1)-- Render on macOS theme --
[Mac] Render Button: OK
[Mac] Render Button: Cancel
[Mac] Render Checkbox: Remember me (checked=0)
[Mac] Click Button: OK
[Mac] Toggle Checkbox -> 1
[Mac] Render Checkbox: Remember me (checked=1)
3.在RT-Thread中的应用

设备注册与创建,比如 rt_device_register()rt_pin_register()。集中创建和初始化对象(设备),并统一放到全局对象管理链表里。

rt_err_t rt_device_register(rt_device_t dev, const char *name, rt_uint16_t flags)
{dev->flag = flags;rt_object_init(&(dev->parent), RT_Object_Class_Device, name);// 加入全局设备链表
}

所有设备通过“工厂”注册。  创建(注册)与使用(init open read .....)分离。

http://www.xdnf.cn/news/17768.html

相关文章:

  • vue2和vue3的区别
  • httpx 设置速率控制 limit 时需要注意 timeout 包含 pool 中等待时间
  • 【2025年 Arxiv 即插即用】 特征融合新突破:空间–光谱注意力融合模块 SAFFM 强势登场!
  • Vite 为什么比 Webpack 快?原理深度分析
  • 【Linux系统】进程的生命旅程:从创建到独立的演绎
  • RTC时钟倒计时数码管同步显示实现(STC8)
  • 如何安装 scikit-learn Python 库
  • 8. 函数简介
  • 鸿蒙NEXT如何通过userAgent区分手机端和pc端
  • 全栈:SSM项目的分支结构以及对应的每个的文件的作用
  • 古中医学习笔记专题文章导航
  • Stability AI技术浅析(一)
  • 力扣top100(day03-02)--图论
  • 【Java虚拟机】JVM相关面试题
  • RabbitMQ高级特性——消息确认、持久性、发送方确认、重试
  • tlias智能学习辅助系统--Maven 高级-私服介绍与资源上传下载
  • 反射在Spring IOC容器中的应用——动态创建Bean (补充)
  • Elasticsearch RBAC 配置:打造多租户环境的安全访问控制
  • CMake语法与Bash语法的区别
  • CV 医学影像分类、分割、目标检测,之【3D肝脏分割】项目拆解
  • 图论Day2学习心得
  • YouBallin正式上线:用Web3重塑创作者经济
  • 强化学习进化之路(GRPO->DAPO->Dr.GRPO->CISPO->GSPO)
  • 自由学习记录(84)
  • 回归算法:驱动酒店智能化定价与自动化运营的引擎—仙盟创梦IDE
  • STL容器详解:Vector高效使用指南
  • 机器学习(一)
  • [论文阅读] 人工智能 + 软件工程 | 从模糊到精准:模块化LLM agents(REQINONE)如何重塑SRS生成
  • 给电脑升级内存,自检太慢,以为出错
  • HTTPS 工作原理