C 語言設計模式(行為型)

文章目錄

  • 策略模式
    • 場景
    • 示例
  • 迭代器模式
    • 場景
    • 示例
  • 訪問者模式
    • 場景
    • 示例
  • 觀察者模式
    • 場景
    • 示例
  • 命令模式
    • 場景
    • 示例
  • 模板方法模式
    • 場景
    • 示例
  • 事件驅動模式
    • 場景
    • 示例
  • 責任鏈模式
    • 場景
    • 示例
  • 狀態模式
    • 場景
    • 示例

策略模式

策略模式(Strategy Pattern)是一種行為型設計模式,它定義了一系列算法,并將每個算法封裝成獨立的對象,使得它們可以互相替換。策略模式使得算法的變化獨立于使用算法的客戶端,從而提高了系統的靈活性和可維護性。

  1. Context(上下文):上下文是使用算法的客戶端對象,它包含一個指向策略對象的引用,并在需要時調用策略對象的算法。上下文對象通常會將請求委托給策略對象來執行。

  2. Strategy(策略):策略是一個接口或者抽象類,它定義了一個算法族,并將每個算法封裝成一個具體的策略對象。所有具體策略對象都實現了相同的接口或者抽象類。

  3. ConcreteStrategy(具體策略):具體策略是策略接口的實現類,它實現了具體的算法邏輯。當客戶端需要使用某種算法時,可以將相應的具體策略對象傳遞給上下文對象,從而使得上下文對象可以調用該算法。

場景

  1. 排序算法:在排序算法中,可能需要根據數據的不同特征選擇不同的排序算法,比如快速排序、歸并排序或者插入排序。可以將每種排序算法封裝成一個策略,然后根據需要在運行時選擇使用哪種策略。

  2. 數據壓縮:在數據壓縮領域,可能存在多種壓縮算法,如LZW、Huffman等。通過使用策略模式,可以根據不同的壓縮需求選擇不同的算法。

  3. 圖像處理:在圖像處理中,可能需要根據圖像的特征選擇不同的處理算法,比如模糊、銳化、邊緣檢測等。通過使用策略模式,可以將每種處理算法封裝成一個策略,然后根據需要選擇不同的策略。

  4. 網絡協議:在網絡編程中,可能需要根據不同的網絡協議選擇不同的處理方式,比如TCP、UDP等。通過使用策略模式,可以將每種協議的處理方式封裝成一個策略,然后根據需要選擇不同的策略。

示例

#include <stdio.h>// 支付信息結構體
typedef struct {float amount;   // 支付金額const char *orderId;   // 訂單ID
} PaymentInfo;// 支付策略接口
typedef struct {void (*pay)(PaymentInfo);  // 支付函數指針
} PaymentStrategy;// 信用卡支付策略
void creditCardPayment(PaymentInfo paymentInfo) {printf("使用信用卡支付 %.2f 元,訂單號:%s\n", paymentInfo.amount, paymentInfo.orderId);// 添加信用卡支付的具體實現
}// 支付寶支付策略
void alipayPayment(PaymentInfo paymentInfo) {printf("使用支付寶支付 %.2f 元,訂單號:%s\n", paymentInfo.amount, paymentInfo.orderId);// 添加支付寶支付的具體實現
}// 微信支付策略
void wechatPayment(PaymentInfo paymentInfo) {printf("使用微信支付 %.2f 元,訂單號:%s\n", paymentInfo.amount, paymentInfo.orderId);// 添加微信支付的具體實現
}// 根據支付方式選擇支付策略
void makePayment(PaymentInfo paymentInfo, PaymentStrategy *strategy) {strategy->pay(paymentInfo);
}int main() {PaymentInfo paymentInfo = {100.00, "123456789"}; // 支付金額為100元,訂單號為123456789// 不同的支付策略PaymentStrategy creditCardStrategy = {creditCardPayment};PaymentStrategy alipayStrategy = {alipayPayment};PaymentStrategy wechatStrategy = {wechatPayment};// 信用卡支付makePayment(paymentInfo, &creditCardStrategy);// 支付寶支付makePayment(paymentInfo, &alipayStrategy);// 微信支付makePayment(paymentInfo, &wechatStrategy);return 0;
}
  • 輸出結果
使用信用卡支付 100.00 元,訂單號:123456789
使用支付寶支付 100.00 元,訂單號:123456789
使用微信支付 100.00 元,訂單號:123456789

迭代器模式

迭代器模式(Iterator Pattern)是一種行為型設計模式,它提供一種方法來順序訪問一個聚合對象中的各個元素,而又不暴露該對象的內部表示。通過使用迭代器模式,可以在不了解聚合對象內部結構的情況下,對聚合對象中的元素進行遍歷操作。

  1. Iterator(迭代器):迭代器是一個接口或者抽象類,它定義了訪問和遍歷聚合對象中各個元素的方法。具體的迭代器實現類負責實現這些方法,以實現對不同類型聚合對象的遍歷操作。

  2. ConcreteIterator(具體迭代器):具體迭代器是迭代器接口的實現類,它實現了對具體聚合對象的遍歷操作。具體迭代器對象會跟蹤遍歷過程中的當前位置,并提供訪問和遍歷下一個元素的方法。

  3. Aggregate(聚合對象):聚合對象是一個接口或者抽象類,它定義了創建迭代器對象的方法。具體的聚合對象實現類負責實現這些方法,并提供迭代器對象用于遍歷聚合對象中的元素。

  4. ConcreteAggregate(具體聚合對象):具體聚合對象是聚合對象接口的實現類,它實現了創建具體迭代器對象的方法,并提供了訪問聚合對象中各個元素的方法。

場景

  1. 數據結構遍歷:迭代器模式最典型的應用場景就是對數據結構的遍歷,比如鏈表、數組、樹等。通過將遍歷算法封裝在迭代器中,可以將數據結構的具體實現和遍歷邏輯分離開來,使得遍歷過程更加靈活。

  2. 文件處理:在文件處理中,可能需要逐行讀取文件內容或者按照一定規則遍歷文件中的數據。使用迭代器模式可以將文件讀取的邏輯抽象為迭代器,從而可以在不同的文件類型或者數據結構上使用相同的遍歷算法。

  3. 內存管理:在操作內存數據結構時,比如堆、棧等,可能需要遍歷內存中的數據或者對內存中的數據進行操作。通過使用迭代器模式,可以將對內存數據結構的遍歷和操作與具體的數據結構分離開來,提高代碼的靈活性和可維護性。

  4. 數據庫查詢:在數據庫操作中,可能需要對查詢結果進行遍歷和處理。使用迭代器模式可以將查詢結果封裝為迭代器,從而可以在不同的數據庫查詢結果上使用相同的遍歷算法。

  5. 圖形界面編程:在圖形界面編程中,可能需要遍歷界面中的控件或者元素。使用迭代器模式可以將界面中的控件或者元素抽象為迭代器,從而可以在不同的界面布局上使用相同的遍歷算法。

示例

#include <stdio.h>// 整數數組結構體
typedef struct {int *data; // 整數數組指針int size;  // 數組大小
} IntArray;// 迭代器結構體
typedef struct {const IntArray *array;  // 指向要迭代的數組的指針int index;              // 當前迭代的索引
} IntArrayIterator;// 初始化整數數組
void initIntArray(IntArray *array, int *data, int size) {array->data = data;array->size = size;
}// 初始化迭代器
void initIntArrayIterator(IntArrayIterator *iterator, const IntArray *array) {iterator->array = array;iterator->index = 0;
}// 獲取迭代器當前指向的元素
int getIntArrayIteratorCurrent(const IntArrayIterator *iterator) {return iterator->array->data[iterator->index];
}// 移動迭代器到下一個元素
void moveIntArrayIteratorNext(IntArrayIterator *iterator) {++iterator->index;
}// 判斷迭代器是否到達末尾
int isIntArrayIteratorEnd(const IntArrayIterator *iterator) {return iterator->index >= iterator->array->size;
}int main() {int data[] = {1, 2, 3, 4, 5};IntArray array;initIntArray(&array, data, sizeof(data) / sizeof(data[0]));IntArrayIterator iterator;initIntArrayIterator(&iterator, &array);// 遍歷整數數組并輸出while (!isIntArrayIteratorEnd(&iterator)) {printf("%d ", getIntArrayIteratorCurrent(&iterator));moveIntArrayIteratorNext(&iterator);}printf("\n");return 0;
}
  • 輸出結果
1 2 3 4 5 

訪問者模式

訪問者模式(Visitor Pattern)是一種行為型設計模式,它可以在不修改對象結構的情況下,定義新的操作或算法并應用于對象的元素。該模式使得可以在不改變元素類的前提下,增加新的操作方式。

  1. Visitor(訪問者):訪問者是一個接口或者抽象類,它定義了對每個元素對象進行操作的方法,這些方法的參數類型決定了哪些對象可以被訪問以及如何訪問它們。

  2. ConcreteVisitor(具體訪問者):具體訪問者是Visitor接口的實現類,它實現了對元素對象的具體操作邏輯。

  3. Element(元素):元素是一個接口或者抽象類,它定義了一個accept方法,該方法接受訪問者對象作為參數,以便讓訪問者對象訪問它。

  4. ConcreteElement(具體元素):具體元素是Element接口的實現類,它實現了accept方法,并在其中調用訪問者對象的相應方法。

  5. ObjectStructure(對象結構):對象結構是一個集合,它用于存儲元素對象,并提供一個接受訪問者對象的方法,以便訪問者可以訪問其中的元素對象。

場景

  1. 抽象語法樹(AST)的遍歷和操作:在編譯器開發中,抽象語法樹(AST)用于表示源代碼的結構,而訪問者模式可以用于遍歷和操作這種復雜的數據結構。通過定義不同的訪問者,可以實現不同的操作,比如語法檢查、代碼生成等。

  2. 文件解析和處理:在文件解析和處理過程中,可能需要根據文件的不同類型執行不同的操作,比如解析XML文件、JSON文件等。訪問者模式可以將對文件的操作抽象為訪問者,從而可以在不同類型的文件上應用相同的操作。

  3. 數據結構的序列化和反序列化:在將數據結構序列化為字節流或者反序列化為數據結構時,可能需要對數據結構的不同部分進行不同的處理。訪問者模式可以將序列化和反序列化的操作抽象為訪問者,從而可以在不同的數據結構上應用相同的操作。

  4. 圖形界面的事件處理:在圖形界面編程中,可能需要對不同的界面元素執行不同的操作,比如按鈕點擊事件、鼠標移動事件等。訪問者模式可以將事件處理邏輯抽象為訪問者,從而可以在不同的界面元素上應用相同的事件處理邏輯。

  5. 數據庫查詢和操作:在數據庫編程中,可能需要對不同的數據庫表執行不同的操作,比如查詢數據、更新數據等。訪問者模式可以將對數據庫表的操作抽象為訪問者,從而可以在不同的數據庫表上應用相同的操作。

示例

#include <stdio.h>// 前置聲明,以便互相引用
typedef struct Circle Circle;
typedef struct Rectangle Rectangle;// 訪問者結構體聲明
typedef struct {// 訪問不同圖形的函數指針void (*visitCircle)(Circle *circle);void (*visitRectangle)(Rectangle *rectangle);
} Visitor;// 圓形結構體聲明
struct Circle {int radius; // 半徑
};// 矩形結構體聲明
struct Rectangle {int width;  // 寬度int height; // 高度
};// 圓形的accept方法
void circleAccept(Visitor *visitor, Circle *circle) {visitor->visitCircle(circle);
}// 矩形的accept方法
void rectangleAccept(Visitor *visitor, Rectangle *rectangle) {visitor->visitRectangle(rectangle);
}// 計算圓形面積的visit方法
void calculateCircleArea(Circle *circle) {float area = 3.14 * circle->radius * circle->radius;printf("圓形面積:%f\n", area);
}// 計算矩形面積的visit方法
void calculateRectangleArea(Rectangle *rectangle) {float area = rectangle->width * rectangle->height;printf("矩形面積:%f\n", area);
}int main() {// 創建訪問者Visitor areaCalculator = {.visitCircle = calculateCircleArea,.visitRectangle = calculateRectangleArea};// 創建圖形Circle circle = {5};Rectangle rectangle = {4, 6};// 計算圖形面積circleAccept(&areaCalculator, &circle);rectangleAccept(&areaCalculator, &rectangle);return 0;
}
  • 輸出結果
圓形面積:78.500000
矩形面積:24.000000

觀察者模式

觀察者模式(Observer Pattern)是一種行為型設計模式,用于定義對象之間的一對多依賴關系,當一個對象的狀態發生變化時,所有依賴它的對象都會得到通知并自動更新。這種模式也被稱為發布-訂閱模式。

  1. Subject(主題):主題是被觀察的對象,它包含了一組觀察者對象,并提供了方法來注冊、刪除和通知觀察者。當主題的狀態發生變化時,它會通知所有注冊的觀察者。

  2. Observer(觀察者):觀察者是訂閱主題的對象,它定義了一個接口,當接收到主題的通知時,可以執行相應的操作。每個觀察者都必須實現這個接口,以便主題能夠調用它們的更新方法。

場景

  1. 事件處理和消息傳遞系統:在事件驅動的系統中,觀察者模式非常有用。當一個事件發生時,所有注冊的觀察者都會收到通知并執行相應的操作。這種模式在圖形用戶界面(GUI)編程中尤其常見,例如,當用戶點擊按鈕時,所有注冊的事件處理程序都會收到通知并執行相應的操作。

  2. 發布-訂閱模式:觀察者模式的一種變體是發布-訂閱模式。在這種模式中,發布者(也稱為主題或事件總線)負責向所有訂閱者(觀察者)發布消息或事件。這種模式在消息隊列系統、即時通訊應用程序等領域被廣泛應用。

  3. 狀態變化通知:當一個對象的狀態發生變化時,它可能需要通知其他對象以執行相應的操作。例如,在游戲開發中,一個玩家對象的狀態變化(比如生命值減少)可能需要通知其他玩家或者游戲引擎來執行相應的動作。

  4. 數據變更通知:在軟件開發中,當一個數據模型的狀態發生變化時,可能需要通知所有依賴該數據模型的視圖或者其他組件進行更新。觀察者模式可以用于實現這種數據變更通知機制。

  5. 日志記錄和錯誤處理:在應用程序中,觀察者模式可以用于實現日志記錄和錯誤處理機制。當發生錯誤或者異常時,可以通知所有注冊的日志記錄器進行記錄,并且通知所有注冊的錯誤處理程序進行處理。

示例

#include <stdio.h>// 觀察者結構體聲明
typedef struct {void (*update)(void); // 更新方法指針
} Observer;// 主題結構體聲明
typedef struct {Observer *observers[10]; // 最多支持10個觀察者int count; // 當前觀察者數量
} Subject;// 初始化主題
void initSubject(Subject *subject) {subject->count = 0;
}// 注冊觀察者
void attachObserver(Subject *subject, Observer *observer) {if (subject->count < 10) {subject->observers[subject->count++] = observer;} else {printf("無法注冊觀察者,已達到最大數量\n");}
}// 更新所有觀察者
void notifyObservers(Subject *subject) {for (int i = 0; i < subject->count; ++i) {subject->observers[i]->update();}
}// 觀察者A的更新方法
void observerAUpdate() {printf("觀察者A收到通知,執行更新操作\n");
}// 觀察者B的更新方法
void observerBUpdate() {printf("觀察者B收到通知,執行更新操作\n");
}int main() {// 創建主題和觀察者Subject subject;Observer observerA = {observerAUpdate};Observer observerB = {observerBUpdate};// 初始化主題initSubject(&subject);// 注冊觀察者attachObserver(&subject, &observerA);attachObserver(&subject, &observerB);// 主題狀態變化,通知所有觀察者notifyObservers(&subject);return 0;
}
  • 輸出結果
觀察者A收到通知,執行更新操作
觀察者B收到通知,執行更新操作

命令模式

命令模式(Command Pattern)是一種行為型設計模式,它用于將請求或操作封裝為獨立的對象,從而使得請求的發送者和接收者之間解耦。在命令模式中,請求被封裝成一個命令對象,請求的發送者(客戶端)只需創建命令對象并將其發送給接收者(調用者),而無需了解命令的具體實現方式。

  1. Command(命令):命令是一個接口或者抽象類,它定義了執行操作的方法。具體的命令對象實現了這個接口,并負責實現具體的操作邏輯。

  2. ConcreteCommand(具體命令):具體命令是命令接口的實現類,它封裝了請求的接收者和執行操作的具體邏輯。

  3. Invoker(調用者):調用者是負責調用命令對象的對象,它只負責向命令對象發送請求,而無需了解命令的具體實現方式。

  4. Receiver(接收者):接收者是命令的實際執行者,它負責執行具體的操作。命令對象將請求委托給接收者來執行。

場景

  1. 圖形用戶界面(GUI)編程:在圖形用戶界面中,用戶的操作(比如點擊按鈕、菜單項等)需要觸發相應的操作。命令模式可以將這些操作封裝為命令對象,并將其發送給對應的接收者(控件或者界面元素)來執行。

  2. 多線程任務調度:在多線程編程中,可能需要將一些操作封裝成任務,并將這些任務交給線程池來執行。命令模式可以將任務封裝為命令對象,并將其發送給線程池來執行。

  3. 日志記錄:在軟件開發中,可能需要記錄系統的操作日志。命令模式可以將記錄日志的操作封裝為命令對象,并將其發送給日志記錄器來執行。

  4. 設備控制:在嵌入式系統或者硬件控制領域,可能需要控制一些設備或者執行一些特定的操作。命令模式可以將這些操作封裝為命令對象,并將其發送給設備控制器來執行。

  5. 文本編輯器的撤銷/重做功能:在文本編輯器中,用戶的操作(比如添加文本、刪除文本等)可能需要支持撤銷和重做功能。命令模式可以將用戶的操作封裝為命令對象,并將其保存在命令歷史記錄中,從而支持撤銷和重做操作。

示例

#include <stdio.h>
#include <stdlib.h>
#include <string.h>// 定義命令接口
typedef struct {void (*execute)(void);      // 執行命令的函數指針void (*undo)(void);         // 撤銷命令的函數指針
} Command;// 添加文本命令
typedef struct {Command base;               // 基類命令char *text;                 // 要添加的文本
} AddTextCommand;// 刪除文本命令
typedef struct {Command base;               // 基類命令char *text;                 // 要刪除的文本
} DeleteTextCommand;// 文本編輯器
typedef struct {char *content;              // 文本內容
} TextEditor;// 執行添加文本命令
void executeAddTextCommand(AddTextCommand *command) {printf("添加文本:%s\n", command->text);// 實際執行添加文本的操作
}// 執行刪除文本命令
void executeDeleteTextCommand(DeleteTextCommand *command) {printf("刪除文本:%s\n", command->text);// 實際執行刪除文本的操作
}// 撤銷添加文本命令
void undoAddTextCommand(AddTextCommand *command) {printf("撤銷添加文本:%s\n", command->text);// 實際執行撤銷添加文本的操作
}// 撤銷刪除文本命令
void undoDeleteTextCommand(DeleteTextCommand *command) {printf("撤銷刪除文本:%s\n", command->text);// 實際執行撤銷刪除文本的操作
}// 初始化文本編輯器
void initTextEditor(TextEditor *editor) {editor->content = NULL;
}// 執行命令
void executeCommand(Command *command) {command->execute();
}// 撤銷命令
void undoCommand(Command *command) {command->undo();
}int main() {// 創建文本編輯器TextEditor editor;initTextEditor(&editor);// 創建添加文本命令AddTextCommand addCommand = {.base.execute = (void (*)(void))executeAddTextCommand,.base.undo = (void (*)(void))undoAddTextCommand,.text = "Hello, World!"};// 創建刪除文本命令DeleteTextCommand deleteCommand = {.base.execute = (void (*)(void))executeDeleteTextCommand,.base.undo = (void (*)(void))undoDeleteTextCommand,.text = "Hello, World!"};// 執行添加文本命令executeCommand((Command *)&addCommand);// 執行刪除文本命令executeCommand((Command *)&deleteCommand);// 撤銷刪除文本命令undoCommand((Command *)&deleteCommand);return 0;
}
  • 輸出結果
添加文本:Hello, World!
刪除文本:Hello, World!
撤銷刪除文本:Hello, World!

模板方法模式

在C語言中,沒有像其他面向對象語言那樣提供原生的類和繼承機制。因此,在C語言中實現傳統意義上的模板方法模式會有一定挑戰。然而,我們可以使用函數指針和回調函數來實現類似的行為。

模板方法模式是一種行為型設計模式,它定義了一個算法的框架,并將其中的一些步驟延遲到子類中實現。模板方法模式通過在父類中定義算法的骨架,并在子類中實現具體的步驟,以達到在運行時選擇不同的行為的目的。

場景

  1. 算法的骨架已經確定,但具體步驟可能變化: 如果有一個算法的骨架已經確定,但其中的某些具體步驟可能會因為應用場景或者其他條件而有所變化,這時可以使用模板方法模式。通過在父類中定義算法的骨架,子類可以根據需要重寫某些步驟,從而實現不同的行為。

  2. 避免代碼重復: 如果有多個算法有相似的流程或步驟,但具體實現略有不同,這時可以將這些共同的部分提取出來,放在父類中作為模板方法,然后子類只需要實現各自特定的步驟,從而避免了代碼的重復。

  3. 實現開閉原則: 模板方法模式可以使得算法的框架穩定不變,而具體的步驟可以靈活變化,從而符合開閉原則,即對擴展開放,對修改關閉。

示例

#include <stdio.h>// 定義函數指針類型,代表算法中的某個步驟
typedef void (*StepFunction)(void);// 父類
typedef struct {StepFunction step1;StepFunction step2;StepFunction step3;
} Template;// 模板方法,定義了算法的框架
void templateMethod(Template *obj) {printf("開始執行模板方法\n");obj->step1();obj->step2();obj->step3();printf("結束執行模板方法\n");
}// 子類1
typedef struct {Template base; // 繼承父類
} ConcreteClass1;// 具體實現子類1的步驟1
void concreteClass1Step1() {printf("子類1:步驟 1\n");
}// 具體實現子類1的步驟2
void concreteClass1Step2() {printf("子類1:步驟 2\n");
}// 具體實現子類1的步驟3
void concreteClass1Step3() {printf("子類1:步驟 3\n");
}// 子類2
typedef struct {Template base; // 繼承父類
} ConcreteClass2;// 具體實現子類2的步驟1
void concreteClass2Step1() {printf("子類2:步驟 1\n");
}// 具體實現子類2的步驟2
void concreteClass2Step2() {printf("子類2:步驟 2\n");
}// 具體實現子類2的步驟3
void concreteClass2Step3() {printf("子類2:步驟 3\n");
}int main() {// 創建子類1對象ConcreteClass1 obj1;obj1.base.step1 = concreteClass1Step1;obj1.base.step2 = concreteClass1Step2;obj1.base.step3 = concreteClass1Step3;// 創建子類2對象ConcreteClass2 obj2;obj2.base.step1 = concreteClass2Step1;obj2.base.step2 = concreteClass2Step2;obj2.base.step3 = concreteClass2Step3;// 使用模板方法templateMethod((Template *)&obj1);templateMethod((Template *)&obj2);return 0;
}
  • 輸出結果
開始執行模板方法
子類1:步驟 1
子類1:步驟 2
子類1:步驟 3
結束執行模板方法
開始執行模板方法
子類2:步驟 1
子類2:步驟 2
子類2:步驟 3
結束執行模板方法

事件驅動模式

事件驅動模式是一種軟件設計模式,它基于事件和事件處理機制。在事件驅動模式中,程序的執行流程是由外部事件的發生和相應的事件處理程序的執行來驅動的。

  1. 事件(Event):事件是程序運行過程中發生的某種事情或者狀態變化,可以是用戶的輸入、系統的消息、定時器的觸發等。事件可以分為不同的類型,每種類型的事件都有相應的處理程序。

  2. 事件處理程序(Event Handler):事件處理程序是針對特定類型的事件而設計的函數或者方法。當特定類型的事件發生時,相應的事件處理程序會被調用來處理事件,執行相應的邏輯。

  3. 事件循環(Event Loop):事件循環是一個在程序中持續運行的循環,它負責等待事件的發生,并將事件分派給相應的事件處理程序。事件循環不斷地從事件隊列中獲取事件,然后根據事件的類型找到相應的事件處理程序來處理事件。

  4. 回調函數(Callback Function):回調函數是一種特殊的函數,它作為參數傳遞給其他函數,在特定的事件發生時被調用。在事件驅動模式中,回調函數通常用于實現事件處理程序,當特定類型的事件發生時,相應的回調函數會被調用來處理事件。

事件驅動模式的核心思想是將程序的控制權交給事件循環,由事件循環負責等待事件的發生,并將事件分派給相應的事件處理程序來處理。這種方式使得程序能夠異步地響應外部事件,提高了程序的并發性和響應速度。

場景

  1. 圖形用戶界面(GUI)編程: 在圖形用戶界面應用程序中,用戶的操作(例如點擊按鈕、輸入文本等)會觸發各種事件,程序需要根據這些事件來執行相應的操作。事件驅動模式可以用于處理用戶交互事件,例如按鈕點擊事件、鼠標移動事件等。

  2. 網絡編程: 在網絡編程中,網絡事件(例如連接建立、數據到達、連接關閉等)會觸發相應的事件處理程序,用于處理這些事件并執行相應的操作。事件驅動模式可以用于實現異步的網絡通信,提高程序的并發性和響應速度。

  3. 多線程編程: 在多線程編程中,線程的運行是由事件和信號來驅動的。例如,一個線程可以等待某個條件變量的信號,一旦條件變量發生變化,就會觸發相應的事件處理程序來執行相應的操作。事件驅動模式可以用于實現多線程編程中的事件驅動模型,提高程序的并發性和可維護性。

  4. 系統級編程: 在系統級編程中,操作系統會產生各種事件,例如定時器事件、硬件中斷事件等。程序需要根據這些事件來執行相應的操作,以實現系統的各種功能。事件驅動模式可以用于處理系統級事件,實現系統級功能。

示例

#include <stdio.h>// 定義事件類型枚舉
typedef enum {BUTTON_CLICK_EVENT,KEY_PRESS_EVENT
} EventType;// 定義事件結構體
typedef struct {EventType type;int data; // 事件數據,例如按鈕編號、按鍵鍵值等
} Event;// 定義事件處理函數類型
typedef void (*EventHandler)(Event *);// 定義按鈕點擊事件處理函數
void buttonClickHandler(Event *event) {printf("處理按鈕點擊事件,按鈕編號:%d\n", event->data);
}// 定義按鍵按下事件處理函數
void keyPressHandler(Event *event) {printf("處理按鍵按下事件,鍵值:%d\n", event->data);
}// 模擬事件循環
void eventLoop() {// 假設有一系列事件需要處理Event events[] = {{BUTTON_CLICK_EVENT, 1}, // 模擬按鈕1被點擊事件{KEY_PRESS_EVENT, 65}    // 模擬按鍵'A'被按下事件};// 處理事件for (int i = 0; i < sizeof(events) / sizeof(Event); i++) {Event event = events[i];switch (event.type) {case BUTTON_CLICK_EVENT:buttonClickHandler(&event); // 調用按鈕點擊事件處理函數break;case KEY_PRESS_EVENT:keyPressHandler(&event);   // 調用按鍵按下事件處理函數break;default:printf("未知事件類型\n");}}
}int main() {// 啟動事件循環eventLoop();return 0;
}
  • 輸出結果
處理按鈕點擊事件,按鈕編號:1
處理按鍵按下事件,鍵值:65

責任鏈模式

責任鏈模式是一種行為型設計模式,用于組織處理對象的責任鏈。在責任鏈模式中,多個對象依次處理請求,直到其中一個對象能夠處理該請求為止。每個處理對象都持有對下一個處理對象的引用,形成一個鏈條。請求沿著這條鏈條依次傳遞,直到被處理。

  1. 抽象處理者(Handler): 定義了一個處理請求的接口,通常包含一個處理請求的方法。可以有多個具體處理者實現這個接口。

  2. 具體處理者(Concrete Handler): 實現了抽象處理者接口,負責處理特定類型的請求。如果自己無法處理請求,則將請求傳遞給下一個處理者。

  3. 客戶端(Client): 創建責任鏈,并向責任鏈中的第一個處理者發送請求。

場景

  1. 系統調用處理: 在操作系統中,可以使用責任鏈模式來處理系統調用。不同的系統調用可能需要由不同的處理程序來處理,責任鏈模式可以根據系統調用的類型將請求傳遞給相應的處理程序來處理。

  2. 事件處理: 在圖形用戶界面(GUI)編程中,可以使用責任鏈模式來處理各種用戶事件,例如鼠標點擊事件、鍵盤按鍵事件等。每個事件可能需要由不同的處理程序來處理,責任鏈模式可以根據事件的類型將請求傳遞給相應的處理程序來處理。

  3. 請求過濾器: 在網絡服務器中,可以使用責任鏈模式來處理請求過濾器。請求過濾器用于過濾和處理傳入的請求,例如對請求進行身份驗證、權限檢查等。責任鏈模式可以根據請求的類型將請求傳遞給相應的過濾器來處理。

  4. 日志記錄: 在日志記錄系統中,可以使用責任鏈模式來處理日志記錄請求。不同級別的日志記錄可能需要由不同的處理程序來處理,責任鏈模式可以根據日志記錄的級別將請求傳遞給相應的處理程序來處理。

示例

#include <stdio.h>
#include <stdlib.h>// 職責鏈節點結構體
typedef struct Handler {struct Handler* next;  // 下一個處理節點void (*handleRequest)(struct Handler* handler, int request);  // 處理請求的函數指針
} Handler;// 處理請求的具體實現函數
void handleRequestA(Handler* handler, int request) {if (request <= 10) {printf("請求 %d 由處理者 A 處理\n", request);} else if (handler->next != NULL) {handler->next->handleRequest(handler->next, request);} else {printf("請求 %d 無法處理\n", request);}
}void handleRequestB(Handler* handler, int request) {if (request > 10 && request <= 20) {printf("請求 %d 由處理者 B 處理\n", request);} else if (handler->next != NULL) {handler->next->handleRequest(handler->next, request);} else {printf("請求 %d 無法處理\n", request);}
}void handleRequestC(Handler* handler, int request) {if (request > 20 && request <= 30) {printf("請求 %d 由處理者 C 處理\n", request);} else if (handler->next != NULL) {handler->next->handleRequest(handler->next, request);} else {printf("請求 %d 無法處理\n", request);}
}int main() {// 創建職責鏈節點Handler* handlerA = (Handler*)malloc(sizeof(Handler));Handler* handlerB = (Handler*)malloc(sizeof(Handler));Handler* handlerC = (Handler*)malloc(sizeof(Handler));// 設置處理請求的函數指針handlerA->handleRequest = handleRequestA;handlerB->handleRequest = handleRequestB;handlerC->handleRequest = handleRequestC;// 構建職責鏈handlerA->next = handlerB;handlerB->next = handlerC;handlerC->next = NULL;// 處理請求int request1 = 5;handlerA->handleRequest(handlerA, request1);int request2 = 15;handlerA->handleRequest(handlerA, request2);int request3 = 25;handlerA->handleRequest(handlerA, request3);// 釋放內存free(handlerA);free(handlerB);free(handlerC);return 0;
}
  • 輸出結果
請求 5 由處理者 A 處理
請求 15 由處理者 B 處理
請求 25 由處理者 C 處理

狀態模式

狀態模式是一種行為型設計模式,用于在對象的內部狀態發生變化時改變其行為。狀態模式通過將對象的狀態封裝成獨立的類,并將對象的行為委托給當前狀態對象來實現狀態轉換和行為變化。

在狀態模式中,一個對象可以同時存在多個狀態,但在任何時刻只能處于其中一個狀態。當對象的狀態發生變化時,它會將當前狀態委托給新的狀態對象來處理。狀態對象負責根據當前狀態執行相應的行為,并可能觸發狀態轉換。

在C語言中,狀態模式通常通過函數指針和函數調用來實現。具體來說,每個狀態都可以是一個函數,它負責執行特定狀態下的行為。對象會將當前狀態委托給相應的狀態處理函數來處理行為。

  1. 環境(Context): 環境是包含狀態的對象,它可以維護一個對當前狀態對象的引用,并且在狀態發生變化時將行為委托給當前狀態對象來處理。

  2. 抽象狀態(State): 抽象狀態定義了一個接口,用于封裝環境對象的一個特定狀態對應的行為。

  3. 具體狀態(Concrete State): 具體狀態實現了抽象狀態接口,負責處理環境對象的一個特定狀態下的行為,并可能觸發狀態轉換。

場景

  1. 有限狀態機(FSM): 在嵌入式系統、游戲開發等領域,經常需要使用有限狀態機來描述系統的狀態和狀態之間的轉換。狀態模式可以用于實現有限狀態機,將每個狀態封裝成獨立的狀態對象,根據當前狀態執行相應的行為,并觸發狀態轉換。

  2. 網絡通信協議: 在網絡編程中,通常需要處理各種不同的通信狀態,例如建立連接、發送數據、接收數據、關閉連接等。狀態模式可以用于管理網絡通信協議的狀態,根據當前狀態執行相應的操作,并根據通信過程中的狀態變化來處理事件。

  3. 圖形用戶界面(GUI)編程: 在圖形用戶界面應用程序中,用戶的操作會觸發各種不同的界面狀態,例如按鈕點擊、鼠標移動、鍵盤輸入等。狀態模式可以用于管理界面的狀態,根據用戶操作的不同來改變界面的行為和顯示。

  4. 自動化控制系統: 在自動化控制系統中,通常需要根據各種傳感器的輸入來控制系統的行為,例如溫度控制、壓力控制等。狀態模式可以用于管理系統的控制狀態,根據傳感器的輸入來改變系統的行為和控制策略。

示例

#include <stdio.h>
#include <stdlib.h>// 聲明狀態結構體
typedef struct State State;// 狀態處理函數指針類型
typedef void (*StateFunc)(State *);// 定義狀態結構體
struct State {StateFunc handleRequest; // 處理請求的函數指針
};// 具體狀態1的處理函數
void state1_handleRequest(State *state) {printf("狀態1:處理請求\n");
}// 具體狀態2的處理函數
void state2_handleRequest(State *state) {printf("狀態2:處理請求\n");
}// 具體狀態3的處理函數
void state3_handleRequest(State *state) {printf("狀態3:處理請求\n");
}int main() {// 創建三種狀態對象State state1 = {state1_handleRequest};State state2 = {state2_handleRequest};State state3 = {state3_handleRequest};// 設置狀態轉換關系state1.handleRequest = state2_handleRequest;state2.handleRequest = state3_handleRequest;state3.handleRequest = state1_handleRequest;// 模擬狀態切換和請求處理State *currentState = &state1; // 初始狀態為狀態1for (int i = 0; i < 5; ++i) {// 處理請求currentState->handleRequest(currentState);// 切換狀態currentState = (currentState->handleRequest == state1_handleRequest) ? &state2 :(currentState->handleRequest == state2_handleRequest) ? &state3 : &state1;}return 0;
}
  • 輸出結果
狀態2:處理請求
狀態1:處理請求
狀態3:處理請求
狀態2:處理請求
狀態1:處理請求

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/bicheng/16917.shtml
繁體地址,請注明出處:http://hk.pswp.cn/bicheng/16917.shtml
英文地址,請注明出處:http://en.pswp.cn/bicheng/16917.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

銀行為什么要對網點開展神秘顧客檢測項目?

銀行業面臨的形勢復雜多變&#xff0c;包括技術創新、客戶行為變化、競爭加劇、監管環境變化、全球化與本地化平衡、經濟環境影響以及可持續發展和社會責任等多方面的挑戰和機遇。銀行需要通過種策略&#xff0c;積極應對這些變化&#xff0c;實現可持續發展。其中提升客戶服務…

順序表實現通訊錄項目

目錄 一.實現功能&#xff1a; 二.文件結構 三.代碼實現 1.初始化 2.通訊錄的銷毀 3.通訊錄添加數據 4.通訊錄刪除數據 5.通訊錄的修改 6.展現通訊錄數據 7.通訊錄查找 四.代碼 SeqList.h Contact.h Contact.c test(通訊錄).c 一.實現功能&#xff1a; ?少能夠存…

Samtec技術漫談 | 電動自行車中的傳感器和信號傳輸技術

【摘要/前言】 電動自行車&#xff0c;大家熟悉嗎&#xff1f; 今天的話題似乎是可以喚起大家心底騎車的美好回憶&#xff0c;我們也曾騎車探索過大自然和社區&#xff0c;自行車也是我們曾經不可或缺的便捷交通工具。 懷舊思潮的影響&#xff0c;加持科技的進步&#xff0c…

php 使用phpoffice導出導出excel

荊軻刺秦王 在PHP中&#xff0c;可以使用 PhpSpreadsheet 庫來創建和導出Excel文件。PhpSpreadsheet 是一個純PHP 編寫的組件庫&#xff0c;它使用現代 PHP 寫法&#xff0c;代碼質量和性能比 PHPExcel 高不少&#xff0c;完全可以替代PHPExcel&#xff08;PHPExcel已不再維護…

【HDFS】FSImage加載過程之loadINode過程

普通的loadINode方法(即不是root inode): 根據inode的類型:文件、目錄、鏈接,做不同的加載處理。 // 根據傳入的PB INode的type做不同處理。// 我們下面關注FILE和DIRECTORY兩種類型:private INode loadINode(INodeSection.INode n) {switch (n.getType()) {<

【云原生】Kubernetes中的List-Watch機制詳解與容器生命周期

目錄 引言 一、List-Watch機制概述 &#xff08;一&#xff09;基本概念 &#xff08;二&#xff09;工作機制 1.List操作 2.Watch操作 &#xff08;三&#xff09;數據流向 1.按模塊劃分 2.按整體總結 二、Pod生命周期 &#xff08;一&#xff09;生命周期 1.創建…

CMake-1 cmake簡介及安裝使用

文章目錄 1. CMake 簡單介紹2. CMake 安裝使用 1. CMake 簡單介紹 為什么需要CMake 寫過C語言的都知道&#xff0c;C語言項目使用Makefile進行管理&#xff0c;而隨著項目復雜度的增加 Makefile編寫的難度也隨之增加&#xff0c;而且在不同平臺Makefile 語法規則是不一樣的&am…

5款好用的AI寫作軟件,一鍵生成高質量文章

在當今信息快速發展的時代&#xff0c;AI寫作軟件逐漸成為創作者們的得力助手。它們能夠憑借先進的技術和算法&#xff0c;一鍵生成高質量的文章&#xff0c;為創作者們節省大量的創作時間和精力。以下是5款備受好評的AI寫作軟件&#xff0c;下面在本文中分享給大家&#xff0c…

20240522金融讀報:出口信用保險提效蘇易融碳中和機票貸款差異化投放替代數據征信培育壯大數字經濟

1、印發通知從響應速度、承保力度、承包評審要素、產業鏈范圍、定制化、線上化、便利化等方面去充分發揮出口信用保險作用。&#xff08;這也可以作為這個貸款業務擔保時的一個考慮項吧&#xff09; 2、蘇易融&#xff1a;匯集江蘇轄內特定客群信貸產品&#xff0c;可一站式查…

BitConverter類型,Byte數組與其他基本類型數據之間的轉換

BitConvert對于byte數組轉換為其他的基本變量很方便&#xff0c;是我們開發必須要學會的類型轉換&#xff0c;因為我在使用中使用的比較多&#xff0c;創作不易&#xff0c;大家點贊關注收藏。 GetBytes(XX)將基本變量轉換成字節數組&#xff0c;C#在數據存儲在計算機中的方式…

kettle學習之表的輸入輸出

需求 把表A里的數據傳送到表B中&#xff0c;在此之前&#xff0c;清空表B內的數據 表輸入 執行SQL腳本 表輸出

一文帶你學會如何部署個人博客到云服務器,并進行域名備案與解析!

哈嘍&#xff0c;大家好呀&#xff01;這里是碼農后端。之前我給大家介紹了如何快速注冊一個自己的域名&#xff0c;并創建一臺自己的阿里云ECS云服務器。本篇將介紹如何將個人博客部署到云服務器&#xff0c;并進行域名備案與解析。 1、域名備案 注冊了域名并購買了云服務器之…

探索自動化辦公的新境界:批量操作與智能管理

新書上架~&#x1f447;全國包郵奧~ python實用小工具開發教程http://pythontoolsteach.com/3 歡迎關注我&#x1f446;&#xff0c;收藏下次不迷路┗|&#xff40;O′|┛ 嗷~~ 目錄 一、自動化辦公的必要性與價值 二、基礎操作與自動化腳本 三、Python在自動化辦公中的應用…

Meme幣總市值突破630億美元 以太坊ETF獲批意味著代幣化資產“完全安全”

近日&#xff0c;數字貨幣市場再次掀起軒然大波。一方面&#xff0c;Meme幣總市值突破了630億美元&#xff0c;令人瞠目結舌&#xff1b;另一方面&#xff0c;以太坊ETF的獲批也引發了市場的廣泛關注&#xff0c;被視為代幣化資產的“完全安全”標志。 Meme幣總市值飆升 Meme幣…

深圳比創達電子EMC|EMC電磁兼容性行業:挑戰與機遇并存

隨著電子技術的迅猛發展&#xff0c;電磁兼容性&#xff08;EMC&#xff09;已成為各行各業不可忽視的關鍵問題。EMC是指設備或系統在其電磁環境中能正常工作且不對該環境中任何事物構成不能承受的電磁騷擾的能力。 一、EMC電磁兼容性行業的現狀 EMC電磁兼容性行業作為電子技…

[數據集][目標檢測]道路井蓋下水道井蓋開關閉和檢測數據集VOC+YOLO格式407張2類別

數據集格式&#xff1a;Pascal VOC格式YOLO格式(不包含分割路徑的txt文件&#xff0c;僅僅包含jpg圖片以及對應的VOC格式xml文件和yolo格式txt文件) 圖片數量(jpg文件個數)&#xff1a;407 標注數量(xml文件個數)&#xff1a;407 標注數量(txt文件個數)&#xff1a;407 標注類別…

構建php環境、安裝、依賴、nginx配置、ab壓力測試命令

目錄 php簡介 官網php安裝包 選擇下載穩定版本 &#xff08;建議使用此版本&#xff0c;文章以此版本為例&#xff09; 安裝php解析環境 準備工作 安裝依賴 zlib-devel 和 libxml2-devel包。 安裝擴展工具庫 安裝 libmcrypt 安裝 mhash 安裝mcrypt 安裝php 選項含…

深入理解一下棧

1、棧&#xff1a;數據結構 為什么 main()方法 最先執行&#xff0c;最后結束&#xff1f; 當然是因為 main()方法入棧啦。 2、棧&#xff1a;棧內存&#xff0c;主管程序的運行&#xff0c;生命周期和現成同步&#xff1b; 線程結束&#xff0c;棧內內存也就釋放了&#xff0c…

STM32_RCC

1、RCC RCC即Reset and Clock Control&#xff0c;復位和時鐘控制。通過stm32f10x結構圖可以看出RCC控制著stm32的AHB系統總線&#xff0c;而AHB總線又橋接APB1和APB2&#xff0c;分別通過它們控制不同的片上外設。如果要使用某個片上外設的功能&#xff0c;必須先通過…

SpringBoot集成騰訊IM流程

1.application.yaml中添加IM配置信息 #im模塊 im: identifier: admin sdkappid: 1400888888 key: ccf2dc88c1ca232cfabbd24906d5091ab81ba0250224abc 2.封裝IM工具類 Component Getter RefreshScope public class ImAdminSignConfig {/*** 簽名*/private String usersig;…