文章目錄
- 策略模式
- 場景
- 示例
- 迭代器模式
- 場景
- 示例
- 訪問者模式
- 場景
- 示例
- 觀察者模式
- 場景
- 示例
- 命令模式
- 場景
- 示例
- 模板方法模式
- 場景
- 示例
- 事件驅動模式
- 場景
- 示例
- 責任鏈模式
- 場景
- 示例
- 狀態模式
- 場景
- 示例
策略模式
策略模式(Strategy Pattern)是一種行為型設計模式,它定義了一系列算法,并將每個算法封裝成獨立的對象,使得它們可以互相替換。策略模式使得算法的變化獨立于使用算法的客戶端,從而提高了系統的靈活性和可維護性。
-
Context(上下文):上下文是使用算法的客戶端對象,它包含一個指向策略對象的引用,并在需要時調用策略對象的算法。上下文對象通常會將請求委托給策略對象來執行。
-
Strategy(策略):策略是一個接口或者抽象類,它定義了一個算法族,并將每個算法封裝成一個具體的策略對象。所有具體策略對象都實現了相同的接口或者抽象類。
-
ConcreteStrategy(具體策略):具體策略是策略接口的實現類,它實現了具體的算法邏輯。當客戶端需要使用某種算法時,可以將相應的具體策略對象傳遞給上下文對象,從而使得上下文對象可以調用該算法。
場景
-
排序算法:在排序算法中,可能需要根據數據的不同特征選擇不同的排序算法,比如快速排序、歸并排序或者插入排序。可以將每種排序算法封裝成一個策略,然后根據需要在運行時選擇使用哪種策略。
-
數據壓縮:在數據壓縮領域,可能存在多種壓縮算法,如LZW、Huffman等。通過使用策略模式,可以根據不同的壓縮需求選擇不同的算法。
-
圖像處理:在圖像處理中,可能需要根據圖像的特征選擇不同的處理算法,比如模糊、銳化、邊緣檢測等。通過使用策略模式,可以將每種處理算法封裝成一個策略,然后根據需要選擇不同的策略。
-
網絡協議:在網絡編程中,可能需要根據不同的網絡協議選擇不同的處理方式,比如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)是一種行為型設計模式,它提供一種方法來順序訪問一個聚合對象中的各個元素,而又不暴露該對象的內部表示。通過使用迭代器模式,可以在不了解聚合對象內部結構的情況下,對聚合對象中的元素進行遍歷操作。
-
Iterator(迭代器):迭代器是一個接口或者抽象類,它定義了訪問和遍歷聚合對象中各個元素的方法。具體的迭代器實現類負責實現這些方法,以實現對不同類型聚合對象的遍歷操作。
-
ConcreteIterator(具體迭代器):具體迭代器是迭代器接口的實現類,它實現了對具體聚合對象的遍歷操作。具體迭代器對象會跟蹤遍歷過程中的當前位置,并提供訪問和遍歷下一個元素的方法。
-
Aggregate(聚合對象):聚合對象是一個接口或者抽象類,它定義了創建迭代器對象的方法。具體的聚合對象實現類負責實現這些方法,并提供迭代器對象用于遍歷聚合對象中的元素。
-
ConcreteAggregate(具體聚合對象):具體聚合對象是聚合對象接口的實現類,它實現了創建具體迭代器對象的方法,并提供了訪問聚合對象中各個元素的方法。
場景
-
數據結構遍歷:迭代器模式最典型的應用場景就是對數據結構的遍歷,比如鏈表、數組、樹等。通過將遍歷算法封裝在迭代器中,可以將數據結構的具體實現和遍歷邏輯分離開來,使得遍歷過程更加靈活。
-
文件處理:在文件處理中,可能需要逐行讀取文件內容或者按照一定規則遍歷文件中的數據。使用迭代器模式可以將文件讀取的邏輯抽象為迭代器,從而可以在不同的文件類型或者數據結構上使用相同的遍歷算法。
-
內存管理:在操作內存數據結構時,比如堆、棧等,可能需要遍歷內存中的數據或者對內存中的數據進行操作。通過使用迭代器模式,可以將對內存數據結構的遍歷和操作與具體的數據結構分離開來,提高代碼的靈活性和可維護性。
-
數據庫查詢:在數據庫操作中,可能需要對查詢結果進行遍歷和處理。使用迭代器模式可以將查詢結果封裝為迭代器,從而可以在不同的數據庫查詢結果上使用相同的遍歷算法。
-
圖形界面編程:在圖形界面編程中,可能需要遍歷界面中的控件或者元素。使用迭代器模式可以將界面中的控件或者元素抽象為迭代器,從而可以在不同的界面布局上使用相同的遍歷算法。
示例
#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)是一種行為型設計模式,它可以在不修改對象結構的情況下,定義新的操作或算法并應用于對象的元素。該模式使得可以在不改變元素類的前提下,增加新的操作方式。
-
Visitor(訪問者):訪問者是一個接口或者抽象類,它定義了對每個元素對象進行操作的方法,這些方法的參數類型決定了哪些對象可以被訪問以及如何訪問它們。
-
ConcreteVisitor(具體訪問者):具體訪問者是Visitor接口的實現類,它實現了對元素對象的具體操作邏輯。
-
Element(元素):元素是一個接口或者抽象類,它定義了一個accept方法,該方法接受訪問者對象作為參數,以便讓訪問者對象訪問它。
-
ConcreteElement(具體元素):具體元素是Element接口的實現類,它實現了accept方法,并在其中調用訪問者對象的相應方法。
-
ObjectStructure(對象結構):對象結構是一個集合,它用于存儲元素對象,并提供一個接受訪問者對象的方法,以便訪問者可以訪問其中的元素對象。
場景
-
抽象語法樹(AST)的遍歷和操作:在編譯器開發中,抽象語法樹(AST)用于表示源代碼的結構,而訪問者模式可以用于遍歷和操作這種復雜的數據結構。通過定義不同的訪問者,可以實現不同的操作,比如語法檢查、代碼生成等。
-
文件解析和處理:在文件解析和處理過程中,可能需要根據文件的不同類型執行不同的操作,比如解析XML文件、JSON文件等。訪問者模式可以將對文件的操作抽象為訪問者,從而可以在不同類型的文件上應用相同的操作。
-
數據結構的序列化和反序列化:在將數據結構序列化為字節流或者反序列化為數據結構時,可能需要對數據結構的不同部分進行不同的處理。訪問者模式可以將序列化和反序列化的操作抽象為訪問者,從而可以在不同的數據結構上應用相同的操作。
-
圖形界面的事件處理:在圖形界面編程中,可能需要對不同的界面元素執行不同的操作,比如按鈕點擊事件、鼠標移動事件等。訪問者模式可以將事件處理邏輯抽象為訪問者,從而可以在不同的界面元素上應用相同的事件處理邏輯。
-
數據庫查詢和操作:在數據庫編程中,可能需要對不同的數據庫表執行不同的操作,比如查詢數據、更新數據等。訪問者模式可以將對數據庫表的操作抽象為訪問者,從而可以在不同的數據庫表上應用相同的操作。
示例
#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)是一種行為型設計模式,用于定義對象之間的一對多依賴關系,當一個對象的狀態發生變化時,所有依賴它的對象都會得到通知并自動更新。這種模式也被稱為發布-訂閱模式。
-
Subject(主題):主題是被觀察的對象,它包含了一組觀察者對象,并提供了方法來注冊、刪除和通知觀察者。當主題的狀態發生變化時,它會通知所有注冊的觀察者。
-
Observer(觀察者):觀察者是訂閱主題的對象,它定義了一個接口,當接收到主題的通知時,可以執行相應的操作。每個觀察者都必須實現這個接口,以便主題能夠調用它們的更新方法。
場景
-
事件處理和消息傳遞系統:在事件驅動的系統中,觀察者模式非常有用。當一個事件發生時,所有注冊的觀察者都會收到通知并執行相應的操作。這種模式在圖形用戶界面(GUI)編程中尤其常見,例如,當用戶點擊按鈕時,所有注冊的事件處理程序都會收到通知并執行相應的操作。
-
發布-訂閱模式:觀察者模式的一種變體是發布-訂閱模式。在這種模式中,發布者(也稱為主題或事件總線)負責向所有訂閱者(觀察者)發布消息或事件。這種模式在消息隊列系統、即時通訊應用程序等領域被廣泛應用。
-
狀態變化通知:當一個對象的狀態發生變化時,它可能需要通知其他對象以執行相應的操作。例如,在游戲開發中,一個玩家對象的狀態變化(比如生命值減少)可能需要通知其他玩家或者游戲引擎來執行相應的動作。
-
數據變更通知:在軟件開發中,當一個數據模型的狀態發生變化時,可能需要通知所有依賴該數據模型的視圖或者其他組件進行更新。觀察者模式可以用于實現這種數據變更通知機制。
-
日志記錄和錯誤處理:在應用程序中,觀察者模式可以用于實現日志記錄和錯誤處理機制。當發生錯誤或者異常時,可以通知所有注冊的日志記錄器進行記錄,并且通知所有注冊的錯誤處理程序進行處理。
示例
#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)是一種行為型設計模式,它用于將請求或操作封裝為獨立的對象,從而使得請求的發送者和接收者之間解耦。在命令模式中,請求被封裝成一個命令對象,請求的發送者(客戶端)只需創建命令對象并將其發送給接收者(調用者),而無需了解命令的具體實現方式。
-
Command(命令):命令是一個接口或者抽象類,它定義了執行操作的方法。具體的命令對象實現了這個接口,并負責實現具體的操作邏輯。
-
ConcreteCommand(具體命令):具體命令是命令接口的實現類,它封裝了請求的接收者和執行操作的具體邏輯。
-
Invoker(調用者):調用者是負責調用命令對象的對象,它只負責向命令對象發送請求,而無需了解命令的具體實現方式。
-
Receiver(接收者):接收者是命令的實際執行者,它負責執行具體的操作。命令對象將請求委托給接收者來執行。
場景
-
圖形用戶界面(GUI)編程:在圖形用戶界面中,用戶的操作(比如點擊按鈕、菜單項等)需要觸發相應的操作。命令模式可以將這些操作封裝為命令對象,并將其發送給對應的接收者(控件或者界面元素)來執行。
-
多線程任務調度:在多線程編程中,可能需要將一些操作封裝成任務,并將這些任務交給線程池來執行。命令模式可以將任務封裝為命令對象,并將其發送給線程池來執行。
-
日志記錄:在軟件開發中,可能需要記錄系統的操作日志。命令模式可以將記錄日志的操作封裝為命令對象,并將其發送給日志記錄器來執行。
-
設備控制:在嵌入式系統或者硬件控制領域,可能需要控制一些設備或者執行一些特定的操作。命令模式可以將這些操作封裝為命令對象,并將其發送給設備控制器來執行。
-
文本編輯器的撤銷/重做功能:在文本編輯器中,用戶的操作(比如添加文本、刪除文本等)可能需要支持撤銷和重做功能。命令模式可以將用戶的操作封裝為命令對象,并將其保存在命令歷史記錄中,從而支持撤銷和重做操作。
示例
#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語言中實現傳統意義上的模板方法模式會有一定挑戰。然而,我們可以使用函數指針和回調函數來實現類似的行為。
模板方法模式是一種行為型設計模式,它定義了一個算法的框架,并將其中的一些步驟延遲到子類中實現。模板方法模式通過在父類中定義算法的骨架,并在子類中實現具體的步驟,以達到在運行時選擇不同的行為的目的。
場景
-
算法的骨架已經確定,但具體步驟可能變化: 如果有一個算法的骨架已經確定,但其中的某些具體步驟可能會因為應用場景或者其他條件而有所變化,這時可以使用模板方法模式。通過在父類中定義算法的骨架,子類可以根據需要重寫某些步驟,從而實現不同的行為。
-
避免代碼重復: 如果有多個算法有相似的流程或步驟,但具體實現略有不同,這時可以將這些共同的部分提取出來,放在父類中作為模板方法,然后子類只需要實現各自特定的步驟,從而避免了代碼的重復。
-
實現開閉原則: 模板方法模式可以使得算法的框架穩定不變,而具體的步驟可以靈活變化,從而符合開閉原則,即對擴展開放,對修改關閉。
示例
#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
結束執行模板方法
事件驅動模式
事件驅動模式是一種軟件設計模式,它基于事件和事件處理機制。在事件驅動模式中,程序的執行流程是由外部事件的發生和相應的事件處理程序的執行來驅動的。
-
事件(Event):事件是程序運行過程中發生的某種事情或者狀態變化,可以是用戶的輸入、系統的消息、定時器的觸發等。事件可以分為不同的類型,每種類型的事件都有相應的處理程序。
-
事件處理程序(Event Handler):事件處理程序是針對特定類型的事件而設計的函數或者方法。當特定類型的事件發生時,相應的事件處理程序會被調用來處理事件,執行相應的邏輯。
-
事件循環(Event Loop):事件循環是一個在程序中持續運行的循環,它負責等待事件的發生,并將事件分派給相應的事件處理程序。事件循環不斷地從事件隊列中獲取事件,然后根據事件的類型找到相應的事件處理程序來處理事件。
-
回調函數(Callback Function):回調函數是一種特殊的函數,它作為參數傳遞給其他函數,在特定的事件發生時被調用。在事件驅動模式中,回調函數通常用于實現事件處理程序,當特定類型的事件發生時,相應的回調函數會被調用來處理事件。
事件驅動模式的核心思想是將程序的控制權交給事件循環,由事件循環負責等待事件的發生,并將事件分派給相應的事件處理程序來處理。這種方式使得程序能夠異步地響應外部事件,提高了程序的并發性和響應速度。
場景
-
圖形用戶界面(GUI)編程: 在圖形用戶界面應用程序中,用戶的操作(例如點擊按鈕、輸入文本等)會觸發各種事件,程序需要根據這些事件來執行相應的操作。事件驅動模式可以用于處理用戶交互事件,例如按鈕點擊事件、鼠標移動事件等。
-
網絡編程: 在網絡編程中,網絡事件(例如連接建立、數據到達、連接關閉等)會觸發相應的事件處理程序,用于處理這些事件并執行相應的操作。事件驅動模式可以用于實現異步的網絡通信,提高程序的并發性和響應速度。
-
多線程編程: 在多線程編程中,線程的運行是由事件和信號來驅動的。例如,一個線程可以等待某個條件變量的信號,一旦條件變量發生變化,就會觸發相應的事件處理程序來執行相應的操作。事件驅動模式可以用于實現多線程編程中的事件驅動模型,提高程序的并發性和可維護性。
-
系統級編程: 在系統級編程中,操作系統會產生各種事件,例如定時器事件、硬件中斷事件等。程序需要根據這些事件來執行相應的操作,以實現系統的各種功能。事件驅動模式可以用于處理系統級事件,實現系統級功能。
示例
#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
責任鏈模式
責任鏈模式是一種行為型設計模式,用于組織處理對象的責任鏈。在責任鏈模式中,多個對象依次處理請求,直到其中一個對象能夠處理該請求為止。每個處理對象都持有對下一個處理對象的引用,形成一個鏈條。請求沿著這條鏈條依次傳遞,直到被處理。
-
抽象處理者(Handler): 定義了一個處理請求的接口,通常包含一個處理請求的方法。可以有多個具體處理者實現這個接口。
-
具體處理者(Concrete Handler): 實現了抽象處理者接口,負責處理特定類型的請求。如果自己無法處理請求,則將請求傳遞給下一個處理者。
-
客戶端(Client): 創建責任鏈,并向責任鏈中的第一個處理者發送請求。
場景
-
系統調用處理: 在操作系統中,可以使用責任鏈模式來處理系統調用。不同的系統調用可能需要由不同的處理程序來處理,責任鏈模式可以根據系統調用的類型將請求傳遞給相應的處理程序來處理。
-
事件處理: 在圖形用戶界面(GUI)編程中,可以使用責任鏈模式來處理各種用戶事件,例如鼠標點擊事件、鍵盤按鍵事件等。每個事件可能需要由不同的處理程序來處理,責任鏈模式可以根據事件的類型將請求傳遞給相應的處理程序來處理。
-
請求過濾器: 在網絡服務器中,可以使用責任鏈模式來處理請求過濾器。請求過濾器用于過濾和處理傳入的請求,例如對請求進行身份驗證、權限檢查等。責任鏈模式可以根據請求的類型將請求傳遞給相應的過濾器來處理。
-
日志記錄: 在日志記錄系統中,可以使用責任鏈模式來處理日志記錄請求。不同級別的日志記錄可能需要由不同的處理程序來處理,責任鏈模式可以根據日志記錄的級別將請求傳遞給相應的處理程序來處理。
示例
#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語言中,狀態模式通常通過函數指針和函數調用來實現。具體來說,每個狀態都可以是一個函數,它負責執行特定狀態下的行為。對象會將當前狀態委托給相應的狀態處理函數來處理行為。
-
環境(Context): 環境是包含狀態的對象,它可以維護一個對當前狀態對象的引用,并且在狀態發生變化時將行為委托給當前狀態對象來處理。
-
抽象狀態(State): 抽象狀態定義了一個接口,用于封裝環境對象的一個特定狀態對應的行為。
-
具體狀態(Concrete State): 具體狀態實現了抽象狀態接口,負責處理環境對象的一個特定狀態下的行為,并可能觸發狀態轉換。
場景
-
有限狀態機(FSM): 在嵌入式系統、游戲開發等領域,經常需要使用有限狀態機來描述系統的狀態和狀態之間的轉換。狀態模式可以用于實現有限狀態機,將每個狀態封裝成獨立的狀態對象,根據當前狀態執行相應的行為,并觸發狀態轉換。
-
網絡通信協議: 在網絡編程中,通常需要處理各種不同的通信狀態,例如建立連接、發送數據、接收數據、關閉連接等。狀態模式可以用于管理網絡通信協議的狀態,根據當前狀態執行相應的操作,并根據通信過程中的狀態變化來處理事件。
-
圖形用戶界面(GUI)編程: 在圖形用戶界面應用程序中,用戶的操作會觸發各種不同的界面狀態,例如按鈕點擊、鼠標移動、鍵盤輸入等。狀態模式可以用于管理界面的狀態,根據用戶操作的不同來改變界面的行為和顯示。
-
自動化控制系統: 在自動化控制系統中,通常需要根據各種傳感器的輸入來控制系統的行為,例如溫度控制、壓力控制等。狀態模式可以用于管理系統的控制狀態,根據傳感器的輸入來改變系統的行為和控制策略。
示例
#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:處理請求