文章目錄
- 代理模式
- 場景
- 示例
- 門面模式
- 場景
- 示例
- 橋接模式
- 場景
- 示例
- 適配器模式
- 場景
- 示例
- 外觀模式
- 場景
- 示例
- 享元模式
- 場景
- 示例
- 裝飾器模式
- 場景
- 示例
- 組合模式
- 場景
- 示例
代理模式
C語言中,代理模式通常用于實現對象的間接訪問。代理模式是一種結構型設計模式,它允許你提供一個代理對象來控制對另一個對象的訪問。這種類型的設計模式屬于結構型模式,因為它創建了對象的代理,以控制對它們的訪問。
- 抽象主題(Subject):定義了真實主題和代理主題的共同接口,這樣代理就可以用來代替真實主題。
2。 真實主題(Real Subject):定義了實際對象,代理對象是對它的一個引用。代理模式中的大部分工作都由真實主題完成,而代理主要負責將請求傳遞給真實主題。
- 代理主題(Proxy):保存一個引用使得代理可以訪問真實主題,并提供與真實主題相同的接口,這樣客戶端就無需知道代理和真實主題的區別。
代理模式通常被用來解決以下一些問題:
-
遠程代理(Remote Proxy):在不同的地址空間中代表一個對象。這種情況下,代理對象負責將請求和參數進行編碼,并向遠程對象發送請求。
-
虛擬代理(Virtual Proxy):用于按需創建昂貴對象,這樣只有在真正需要時才會實例化真實對象。例如,一個圖像瀏覽器可能只在需要顯示圖像時才會加載真正的圖像數據。
-
保護代理(Protection Proxy):用于控制對對象的訪問,可以根據訪問權限拒絕調用者的請求。
場景
-
文件訪問控制:在一個需要對文件進行訪問控制的系統中,可以使用代理模式來創建一個文件訪問代理,以控制對文件的讀取和寫入操作,實現對文件訪問的安全管理。
-
網絡通信:在網絡通信中,可以使用代理模式來創建網絡通信代理,以控制對網絡資源的訪問,實現網絡通信的安全驗證、加密解密等功能。
-
資源管理:在需要管理共享資源的系統中,可以使用代理模式來創建資源管理代理,以控制對資源的訪問,實現資源的共享和保護。
-
緩存管理:在需要緩存數據以提高性能的系統中,可以使用代理模式來創建緩存代理,以控制對數據的訪問,實現數據的緩存和更新策略。
-
權限管理:在需要對用戶權限進行管理的系統中,可以使用代理模式來創建權限管理代理,以控制對資源的訪問,實現對用戶權限的控制和管理。
示例
#include <stdio.h>
#include <stdlib.h>
#include <string.h>// 定義抽象主題接口
struct File {void (*read)(struct File *);void (*write)(struct File *, const char *);
};// 定義真實主題
struct RealFile {struct File file; // 繼承自抽象主題char *name;
};// 真實主題的讀操作實現
void real_read(struct File *file) {struct RealFile *realFile = (struct RealFile *)file;printf("讀取文件:%s\n", realFile->name);
}// 真實主題的寫操作實現
void real_write(struct File *file, const char *data) {struct RealFile *realFile = (struct RealFile *)file;printf("寫入文件:%s\n", realFile->name);printf("數據:%s\n", data);
}// 定義代理主題
struct ProxyFile {struct File file; // 繼承自抽象主題struct RealFile *realFile;
};// 代理主題的讀操作實現
void proxy_read(struct File *file) {struct ProxyFile *proxyFile = (struct ProxyFile *)file;printf("代理請求讀取...\n");proxyFile->realFile->file.read(&(proxyFile->realFile->file));
}// 代理主題的寫操作實現
void proxy_write(struct File *file, const char *data) {struct ProxyFile *proxyFile = (struct ProxyFile *)file;printf("代理請求寫入...\n");proxyFile->realFile->file.write(&(proxyFile->realFile->file), data);
}int main() {// 創建真實文件對象struct RealFile *realFile = malloc(sizeof(struct RealFile));realFile->name = strdup("example.txt");realFile->file.read = real_read;realFile->file.write = real_write;// 創建文件代理對象struct ProxyFile *proxyFile = malloc(sizeof(struct ProxyFile));proxyFile->realFile = realFile;proxyFile->file.read = proxy_read;proxyFile->file.write = proxy_write;// 使用代理對象讀寫文件proxyFile->file.read(&(proxyFile->file));proxyFile->file.write(&(proxyFile->file), "Hello, Proxy Pattern!");// 釋放內存free(realFile->name);free(realFile);free(proxyFile);return 0;
}
- 輸出結果
代理請求讀取...
讀取文件:example.txt
代理請求寫入...
寫入文件:example.txt
數據:Hello, Proxy Pattern!
門面模式
C語言中,門面模式(Facade Pattern)是一種常見的設計模式,用于提供一個統一的接口,以簡化一組復雜系統的使用。門面模式隱藏了系統的復雜性,為客戶端提供了一個更簡單的接口,從而使客戶端不需要了解系統的內部實現細節。
-
門面(Facade):提供了一個簡單的接口,用于將客戶端的請求委派給系統內部的各個子系統。
-
子系統(Subsystems):實現了系統的各個功能,但是這些功能對客戶端來說可能過于復雜。門面模式通過封裝這些子系統,提供了一個更簡單的接口供客戶端使用。
場景
-
復雜系統的簡化接口:當一個系統由多個子系統組成,而客戶端需要使用的功能較少或者不需要了解系統內部的復雜結構時,門面模式可以提供一個簡化的接口,隱藏系統的復雜性,使得客戶端更容易使用。
-
庫或框架的封裝:當開發一個庫或框架時,為了提供更加友好的接口給用戶使用,可以使用門面模式來封裝庫或框架的內部實現細節,使得用戶只需調用簡單的接口即可完成復雜的操作。
-
遺留系統的接口升級:當需要對一個遺留系統進行接口升級或者重構時,可以使用門面模式來封裝原有的接口,提供一個向后兼容的接口給客戶端使用,從而減少對客戶端的影響。
-
跨平臺開發:當需要在不同平臺上開發應用程序時,可以使用門面模式來封裝不同平臺的差異,提供一個統一的接口給客戶端使用,從而簡化開發工作。
-
系統的分層設計:當一個系統被分為多個層次,每個層次都有不同的責任時,可以使用門面模式來定義每個層次的門面,使得每個層次都可以獨立于其他層次進行開發和測試。
示例
#include <stdio.h>// 子系統1:CPU
struct CPU {void (*run)(struct CPU *);
};// 子系統1的操作實現
void cpu_run(struct CPU *cpu) {printf("CPU開始運行\n");
}// 子系統2:內存
struct Memory {void (*load)(struct Memory *);
};// 子系統2的操作實現
void memory_load(struct Memory *memory) {printf("內存加載數據\n");
}// 子系統3:硬盤
struct HardDrive {void (*read)(struct HardDrive *);
};// 子系統3的操作實現
void harddrive_read(struct HardDrive *hardDrive) {printf("硬盤讀取數據\n");
}// 門面:計算機
struct Computer {struct CPU cpu;struct Memory memory;struct HardDrive hardDrive;void (*start)(struct Computer *);
};// 門面的操作實現
void computer_start(struct Computer *computer) {printf("計算機啟動中...\n");// 啟動計算機時,依次啟動CPU、內存和硬盤computer->cpu.run(&(computer->cpu));computer->memory.load(&(computer->memory));computer->hardDrive.read(&(computer->hardDrive));printf("計算機啟動完成\n");
}int main() {// 創建計算機對象struct Computer computer;// 初始化計算機對象的各個子系統computer.cpu.run = cpu_run;computer.memory.load = memory_load;computer.hardDrive.read = harddrive_read;// 初始化計算機對象的啟動函數computer.start = computer_start;// 使用門面模式啟動計算機computer.start(&computer);return 0;
}
- 輸出結果
計算機啟動中...
CPU開始運行
內存加載數據
硬盤讀取數據
計算機啟動完成
橋接模式
C語言中,橋接模式(Bridge Pattern)是一種結構型設計模式,它將抽象部分與實現部分分離,使它們可以獨立變化。橋接模式通過將抽象部分與實現部分進行解耦,允許它們可以獨立地進行變化,從而提高了系統的靈活性和可擴展性。
-
抽象部分(Abstraction):定義了抽象類接口,維護一個指向實現部分的引用。
-
擴展抽象部分(Refined Abstraction):繼承自抽象部分,擴展了抽象類接口,增加了新的功能或行為。
-
實現部分(Implementor):定義了實現類接口,提供了實現類的基本操作。
-
具體實現部分(Concrete Implementor):實現了實現部分接口的具體類。
場景
-
多維度變化的系統:當一個系統有多個維度的變化,而且這些維度都需要獨立變化時,可以使用橋接模式將不同維度的變化進行解耦。例如,一個圖形界面系統中,可能有多種不同的繪制方式和多種不同的控件類型,可以使用橋接模式將不同的繪制方式和控件類型進行解耦,使得系統更加靈活。
-
運行時切換實現:當一個系統需要在運行時動態地選擇不同的實現時,可以使用橋接模式。例如,一個網絡通信庫可能需要支持多種不同的網絡協議,可以使用橋接模式將不同的網絡協議的實現進行解耦,使得系統可以在運行時動態地選擇不同的網絡協議。
-
多平臺支持:當一個系統需要支持多個不同的平臺時,可以使用橋接模式將不同平臺的實現進行解耦。例如,一個圖形庫可能需要支持在Windows、Linux和macOS等多個平臺上運行,可以使用橋接模式將不同平臺的圖形接口進行解耦,使得系統更易于擴展和維護。
-
數據庫驅動程序:在數據庫訪問層中,不同的數據庫可能有不同的實現方式,可以使用橋接模式將不同數據庫的實現進行解耦,使得系統可以在運行時動態地選擇不同的數據庫實現。
示例
#include <stdio.h>// 實現部分接口
struct Implementor {void (*operationImpl)(void); // 操作實現函數指針
};// 具體實現部分A
void operationImplA() {printf("具體實現部分A的操作\n");
}// 具體實現部分B
void operationImplB() {printf("具體實現部分B的操作\n");
}// 抽象部分
struct Abstraction {struct Implementor *impl; // 實現部分指針void (*operation)(struct Abstraction *); // 操作函數
};// 擴展抽象部分
void operation(struct Abstraction *abstraction) {abstraction->impl->operationImpl(); // 調用實現部分的操作
}int main() {// 創建具體實現部分A的對象struct Implementor implA;implA.operationImpl = operationImplA;// 創建具體實現部分B的對象struct Implementor implB;implB.operationImpl = operationImplB;// 創建抽象部分對象,關聯具體實現部分Astruct Abstraction abstractionA;abstractionA.impl = &implA;abstractionA.operation = operation;// 調用抽象部分的操作,實際執行具體實現部分A的操作abstractionA.operation(&abstractionA);// 創建抽象部分對象,關聯具體實現部分Bstruct Abstraction abstractionB;abstractionB.impl = &implB;abstractionB.operation = operation;// 調用抽象部分的操作,實際執行具體實現部分B的操作abstractionB.operation(&abstractionB);return 0;
}
- 輸出結果
具體實現部分A的操作
具體實現部分B的操作
適配器模式
C語言中,適配器模式(Adapter Pattern)是一種結構型設計模式,它允許接口不兼容的類能夠一起工作。適配器模式通過將一個類的接口轉換成客戶端所期望的另一個接口,從而使得原本由于接口不兼容而不能一起工作的類可以一起工作。
-
目標接口(Target):客戶端期望的接口,適配器模式通過適配器將被適配者的接口轉換成目標接口。
-
被適配者(Adaptee):需要被適配的類,它的接口與目標接口不兼容。
-
適配器(Adapter):實現了目標接口,并包含一個被適配者的對象,它將客戶端的請求轉發給被適配者,并進行適配。
場景
-
使用現有庫或框架:當需要使用一個已經存在的庫或框架,但它的接口與系統的其他部分不兼容時,可以使用適配器模式將它的接口轉換成系統所期望的接口。
-
跨平臺開發:在跨平臺開發中,不同平臺上的API可能存在差異,導致代碼無法跨平臺使用。可以使用適配器模式將不同平臺上的API接口進行統一,使得代碼可以跨平臺使用。
-
日志系統的適配:當系統需要更換日志系統時,可以使用適配器模式將新的日志系統的接口適配成原有日志系統的接口,使得系統可以無縫切換日志系統而不需要修改大量代碼。
-
數據庫訪問的適配:當系統需要支持多種不同的數據庫時,可以使用適配器模式將不同數據庫的訪問接口適配成統一的接口,使得系統可以使用相同的代碼訪問不同的數據庫。
-
設備驅動的適配:當系統需要支持多種不同的硬件設備時,可以使用適配器模式將不同設備的驅動接口適配成統一的接口,使得系統可以使用相同的代碼操作不同的設備。
示例
#include <stdio.h>// 目標接口
struct Target {void (*request)(struct Target *);
};// 被適配者
struct Adaptee {void (*specificRequest)(struct Adaptee *);
};// 被適配者的特定請求實現
void specificRequest(struct Adaptee *adaptee) {printf("被適配者的特定請求\n");
}// 適配器
struct Adapter {struct Target target; // 目標接口struct Adaptee adaptee; // 被適配者
};// 適配器的請求實現
void request(struct Target *target) {// 將目標接口的請求轉發給被適配者的特定請求struct Adapter *adapter = (struct Adapter *)target;adapter->adaptee.specificRequest(&(adapter->adaptee));
}int main() {// 創建被適配者對象struct Adaptee adaptee;adaptee.specificRequest = specificRequest;// 創建適配器對象struct Adapter adapter;adapter.target.request = request;adapter.adaptee = adaptee;// 使用適配器調用目標接口adapter.target.request(&(adapter.target));return 0;
}
- 輸出結果
被適配者的特定請求
外觀模式
外觀模式(Facade Pattern)是一種結構型設計模式,它提供了一個統一的接口,用來訪問子系統中的一群接口。外觀模式定義了一個高層接口,使得子系統更容易使用。
在C語言中,外觀模式可以幫助簡化復雜系統的使用,隱藏系統的復雜性,提供一個更加友好和簡單的接口給客戶端使用。外觀模式通常包含以下幾個角色:
-
外觀(Facade):提供了一個簡單的接口,用來訪問子系統中的一群接口。外觀模式通過將客戶端的請求委派給子系統中的各個對象來實現這個接口。
-
子系統(Subsystems):實現了系統的各個功能,但是這些功能對客戶端來說可能過于復雜。外觀模式通過封裝這些子系統,提供了一個更簡單的接口供客戶端使用。
場景
-
復雜系統的簡化接口:當一個系統由多個子系統組成,而客戶端只需使用其中的一部分功能時,可以使用外觀模式將這些子系統的復雜功能進行封裝,提供一個簡化的接口給客戶端使用。
-
隱藏系統的復雜性:當一個系統的內部結構復雜,而客戶端不需要了解系統的內部實現細節時,可以使用外觀模式隱藏系統的復雜性,提供一個更加友好和簡單的接口給客戶端使用。
-
簡化接口的調用流程:當一個系統的接口調用流程比較繁瑣,需要依次調用多個接口時,可以使用外觀模式將這些接口調用流程進行封裝,提供一個更簡單和直觀的接口給客戶端使用。
-
封裝遺留系統:當一個系統的接口需要向后兼容或者需要與其他系統進行集成時,可以使用外觀模式封裝遺留系統的接口,提供一個統一的接口給客戶端使用,從而降低系統的耦合度。
-
統一接口規范:當一個系統需要支持多種不同的接口規范時,可以使用外觀模式將這些不同的接口規范進行統一,提供一個統一的接口給客戶端使用,使得客戶端可以無需關心不同接口規范的細節。
示例
#include <stdio.h>// 子系統1:CPU
struct CPU {void (*run)(void); // 運行方法
};// 子系統1的具體實現
void cpu_run() {printf("CPU開始運行\n");
}// 子系統2:內存
struct Memory {void (*load)(void); // 加載方法
};// 子系統2的具體實現
void memory_load() {printf("內存加載數據\n");
}// 子系統3:硬盤
struct HardDrive {void (*read)(void); // 讀取方法
};// 子系統3的具體實現
void harddrive_read() {printf("硬盤讀取數據\n");
}// 外觀:計算機
struct ComputerFacade {struct CPU cpu;struct Memory memory;struct HardDrive hardDrive;void (*start)(void); // 啟動方法
};// 外觀的實現
void start() {printf("計算機啟動中...\n");// 啟動計算機時,依次啟動CPU、內存和硬盤cpu_run();memory_load();harddrive_read();printf("計算機啟動完成\n");
}int main() {// 創建外觀對象struct ComputerFacade computerFacade;// 初始化外觀對象的各個子系統computerFacade.cpu.run = cpu_run;computerFacade.memory.load = memory_load;computerFacade.hardDrive.read = harddrive_read;// 初始化外觀對象的啟動方法computerFacade.start = start;// 使用外觀模式啟動計算機computerFacade.start();return 0;
}
- 輸出結果
計算機啟動中...
CPU開始運行
內存加載數據
硬盤讀取數據
計算機啟動完成
享元模式
享元模式(Flyweight Pattern)是一種結構型設計模式,它旨在通過共享對象來最大限度地減少內存使用和提高性能。在享元模式中,將對象的狀態分為內部狀態(Intrinsic State)和外部狀態(Extrinsic State),其中內部狀態可以被多個對象共享,而外部狀態需要根據場景而變化。
-
享元工廠(Flyweight Factory):負責創建和管理享元對象,通過共享已創建的享元對象來減少對象的創建數量。
-
享元接口(Flyweight Interface):定義了享元對象的接口,包括設置外部狀態的方法等。
-
具體享元對象(Concrete Flyweight):實現了享元接口,包含了內部狀態,并對外部狀態進行了處理。
-
客戶端(Client):通過享元工廠獲取享元對象,并設置外部狀態,實現具體的業務邏輯。
場景
-
大量對象的共享:當系統中存在大量相似對象,并且這些對象可以共享部分狀態時,可以使用享元模式來減少對象的創建數量,降低內存消耗。
-
對象的狀態可分為內部狀態和外部狀態:當一個對象的狀態可以分為內部狀態(Intrinsic State)和外部狀態(Extrinsic State),并且內部狀態可以被多個對象共享時,可以使用享元模式來共享內部狀態,減少對象的創建數量。
-
需要緩存對象的場景:當系統需要緩存一些常用的對象,并且這些對象可以共享部分狀態時,可以使用享元模式來緩存這些對象,提高系統的性能。
-
系統需要保持獨立的對象:當系統需要保持獨立的對象,但又希望共享相同的狀態時,可以使用享元模式來共享這些狀態,同時保持對象的獨立性。
-
需要減少系統中對象的數量:當系統中存在大量相似對象,并且這些對象可以共享部分狀態時,可以使用享元模式來減少對象的創建數量,提高系統的性能和資源利用率。
示例
#include <stdio.h>
#include <stdlib.h>
#include <string.h>// 享元對象結構體
typedef struct {char *name; // 內部狀態int size; // 外部狀態
} Flyweight;// 享元工廠
Flyweight *get_flyweight(char *name) {static Flyweight *flyweights[10] = {NULL}; // 預先創建的享元對象數組static int index = 0;// 查找現有的享元對象for (int i = 0; i < index; i++) {if (strcmp(flyweights[i]->name, name) == 0) {return flyweights[i];}}// 創建新的享元對象Flyweight *flyweight = (Flyweight *)malloc(sizeof(Flyweight));flyweight->name = strdup(name);flyweights[index++] = flyweight;return flyweight;
}// 客戶端使用享元對象
void client(char *name, int size) {Flyweight *flyweight = get_flyweight(name);printf("對象名:%s,大小:%d\n", flyweight->name, size);
}int main() {// 客戶端使用享元對象client("object1", 10);client("object2", 20);client("object1", 30); // 復用現有的享元對象client("object3", 15);client("object2", 25); // 復用現有的享元對象return 0;
}
- 輸出結果
對象名:object1,大小:10
對象名:object2,大小:20
對象名:object1,大小:30
對象名:object3,大小:15
對象名:object2,大小:25
裝飾器模式
裝飾器模式(Decorator Pattern)是一種結構型設計模式,它允許向現有對象動態地添加新功能,同時又不改變其結構。裝飾器模式通過創建一個包裝器(Wrapper),將被裝飾的對象進行包裝,從而可以在運行時動態地添加新的功能。
-
組件接口(Component Interface):定義了被裝飾對象和裝飾器共同實現的接口。
-
具體組件(Concrete Component):實現了組件接口的具體對象,它是被裝飾的對象。
-
裝飾器(Decorator):實現了組件接口,并包含了一個指向被裝飾對象的指針,它可以動態地添加新的功能。
-
具體裝飾器(Concrete Decorator):實現了裝飾器接口的具體對象,用于添加新的功能。
場景
-
動態添加功能:當需要在不修改對象的基本結構的情況下,動態地添加額外的功能時,可以使用裝飾器模式。這樣可以避免修改現有的代碼,使得系統更加靈活和可擴展。
-
多個功能的組合:當需要對對象的功能進行組合和排列,以滿足不同的需求時,可以使用裝飾器模式。通過組合不同的裝飾器,可以實現不同的功能組合,而無需創建大量的子類。
-
功能的分層擴展:當需要對對象的功能進行分層擴展,以便于復用和維護時,可以使用裝飾器模式。通過創建不同層次的裝飾器,可以實現對對象功能的分層擴展,從而使得系統更易于理解和維護。
-
功能的獨立擴展:當需要對對象的部分功能進行獨立擴展和修改時,可以使用裝飾器模式。通過創建獨立的裝飾器,可以實現對對象的部分功能進行擴展,而不影響其他功能的使用。
-
動態改變對象的行為:當需要動態地改變對象的行為,以適應不同的場景時,可以使用裝飾器模式。通過在運行時動態地裝飾對象,可以實現對對象行為的動態改變,從而提高系統的靈活性和可定制性。
示例
#include <stdio.h>// 組件接口
typedef struct {void (*operation)(void);
} Component;// 具體組件
typedef struct {Component component;
} ConcreteComponent;// 具體組件的操作實現
void concrete_operation(void) {printf("執行具體組件的操作\n");
}// 裝飾器
typedef struct {Component component;void (*decorate)(Component *);
} Decorator;// 具體裝飾器1
typedef struct {Decorator decorator;
} ConcreteDecorator1;// 具體裝飾器1的裝飾方法
void decorate1(Component *component) {printf("在具體裝飾器1中添加功能1\n");component->operation();
}// 具體裝飾器2
typedef struct {Decorator decorator;
} ConcreteDecorator2;// 具體裝飾器2的裝飾方法
void decorate2(Component *component) {printf("在具體裝飾器2中添加功能2\n");component->operation();
}int main() {// 創建具體組件ConcreteComponent concreteComponent;concreteComponent.component.operation = concrete_operation;// 創建具體裝飾器1,并裝飾具體組件ConcreteDecorator1 concreteDecorator1;concreteDecorator1.decorator.component = concreteComponent.component;concreteDecorator1.decorator.decorate = decorate1;concreteDecorator1.decorator.decorate(&(concreteDecorator1.decorator.component));// 創建具體裝飾器2,并裝飾具體組件ConcreteDecorator2 concreteDecorator2;concreteDecorator2.decorator.component = concreteComponent.component;concreteDecorator2.decorator.decorate = decorate2;concreteDecorator2.decorator.decorate(&(concreteDecorator2.decorator.component));return 0;
}
- 輸出結果
在具體裝飾器1中添加功能1
執行具體組件的操作
在具體裝飾器2中添加功能2
執行具體組件的操作
組合模式
組合模式(Composite Pattern)是一種結構型設計模式,它允許將對象組合成樹形結構以表示“部分-整體”的層次結構。組合模式讓客戶端以統一的方式處理單個對象以及對象組合,從而使得客戶端無需區分對象和對象組合。
-
組件接口(Component Interface):定義了組合中所有對象共同的接口,以便于客戶端統一處理對象和對象組合。
-
葉子組件(Leaf Component):表示組合中的葉子節點,它實現了組件接口,但是沒有子節點。
-
復合組件(Composite Component):表示組合中的復合節點,它實現了組件接口,并且包含了子節點。
場景
-
文件系統:文件系統中的目錄和文件可以使用組合模式來表示。目錄可以看作是復合組件,它包含了多個文件或目錄(葉子組件和復合組件),而文件可以看作是葉子組件,它不包含其他文件或目錄。
-
圖形用戶界面(GUI):圖形用戶界面中的控件和容器可以使用組合模式來表示。控件可以看作是葉子組件,它顯示具體的內容或功能,而容器可以看作是復合組件,它包含了多個控件(葉子組件和復合組件)。
-
組織架構:組織架構中的部門和員工可以使用組合模式來表示。部門可以看作是復合組件,它包含了多個員工(葉子組件和復合組件),而員工可以看作是葉子組件,它不包含其他員工。
-
菜單系統:菜單系統中的菜單項和菜單可以使用組合模式來表示。菜單項可以看作是葉子組件,它表示一個具體的功能或選項,而菜單可以看作是復合組件,它包含了多個菜單項(葉子組件和復合組件)。
-
物品組織:在游戲開發中,物品的組織結構可以使用組合模式來表示。物品可以看作是葉子組件,它表示一個具體的物品,而物品箱或背包可以看作是復合組件,它包含了多個物品(葉子組件和復合組件)。
示例
#include <stdio.h>// 定義組件類型
typedef enum {LEAF, // 葉子節點COMPOSITE // 復合節點
} NodeType;// 定義組件結構體
typedef struct Node {NodeType type; // 節點類型:葉子節點或復合節點char *name; // 節點名稱union {struct Node *child; // 葉子節點指向NULL,復合節點指向子節點鏈表的頭節點struct Node *next; // 復合節點鏈表中的下一個節點} next;
} Node;// 打印節點名稱
void print_node(Node *node) {printf("%s\n", node->name);
}// 打印樹節點
void print_tree(Node *root, int depth) {if (root == NULL) return;// 打印節點名稱for (int i = 0; i < depth; ++i) {printf(" ");}print_node(root);// 遞歸打印子節點if (root->type == COMPOSITE) {print_tree(root->next.child, depth + 1);}// 遞歸打印兄弟節點print_tree(root->next.next, depth);
}int main() {// 創建根節點Node root = {COMPOSITE, "根節點", .next = {NULL}};// 創建子節點Node node1 = {LEAF, "葉子節點1", .next = {NULL}};Node node2 = {LEAF, "葉子節點2", .next = {NULL}};// 創建復合節點Node composite_node = {COMPOSITE, "復合節點", .next = {.child = &node1}};// 將復合節點添加到根節點root.next.next = &composite_node;composite_node.next.next = &node2;// 打印樹節點print_tree(&root, 0);return 0;
}
- 輸出結果
根節點復合節點葉子節點2葉子節點2
復合節點葉子節點2
葉子節點2