創建型模式
工廠方法模式是一種創建型設計模式,?其在父類中提供一個創建對象的方法,?允許子類決定實例化對象的類型。
為什么需要工廠方法模式?
看一個 “沒有工廠模式” 的痛點場景:
假設你在開發一個游戲,最初只有 “戰士” 一種角色,代碼可能這樣寫:
// 早期代碼:直接在客戶端創建對象
void startGame() {// 直接new具體角色Warrior* warrior = new Warrior(); warrior->attack();// ...
}
但隨著游戲迭代,需要添加 “法師” 角色,你不得不修改客戶端代碼:
// 迭代后:客戶端代碼被迫修改
void startGame(std::string roleType) {Character* character;// 客戶端需要知道所有具體角色的類型if (roleType == "warrior") {character = new Warrior();} else if (roleType == "mage") { // 新增邏輯character = new Mage();}character->attack();// ...
}
繼續迭代添加 “弓箭手”“刺客” 時,客戶端代碼會被反復修改,最終變得臃腫且脆弱。
工廠方法優點
1.解耦對象創建與使用
2.符合開閉原則
????????新增產品時,只需添加對應的具體產品類(如Assassin)和具體工廠類(如AssassinFactory),無需修改現有工廠和客戶端代碼。例如要增加 “刺客” 角色,原有的戰士、法師工廠代碼完全不用動。
3.單一職責原則
????????每個具體工廠只負責創建一種產品(如WarriorFactory
只創建戰士),職責清晰,避免了一個類承擔過多創建邏輯。
4.支持多態創建
????????客戶端可以通過相同的接口(抽象工廠)創建不同類型的產品。
5.便于擴展和測試
示例
#include <iostream>
#include <string>
#include <memory>// 產品接口:游戲角色
class Character {
public:virtual ~Character() = default;virtual void attack() const = 0; // 攻擊方法virtual void defend() const = 0; // 防御方法virtual std::string getName() const = 0; // 獲取角色名稱
};// 具體產品1:戰士(近戰高防御)
class Warrior : public Character {
public:void attack() const override {std::cout << "戰士揮舞大劍,進行猛烈劈砍!" << std::endl;}void defend() const override {std::cout << "戰士舉起盾牌,形成堅固防御!" << std::endl;}std::string getName() const override {return "鋼鐵戰士";}
};// 具體產品2:法師(遠程魔法攻擊)
class Mage : public Character {
public:void attack() const override {std::cout << "法師吟唱咒語,釋放火球術!" << std::endl;}void defend() const override {std::cout << "法師召喚魔法屏障,抵御傷害!" << std::endl;}std::string getName() const override {return "元素法師";}
};// 具體產品3:弓箭手(遠程物理攻擊)
class Archer : public Character {
public:void attack() const override {std::cout << "弓箭手拉滿長弓,射出精準箭矢!" << std::endl;}void defend() const override {std::cout << "弓箭手快速后跳,閃避攻擊!" << std::endl;}std::string getName() const override {return "精靈弓箭手";}
};// 抽象工廠:角色創建工廠
class CharacterFactory {
public:virtual ~CharacterFactory() = default;virtual std::unique_ptr<Character> createCharacter() = 0; // 工廠方法:創建角色
};// 具體工廠1:戰士工廠
class WarriorFactory : public CharacterFactory {
public:std::unique_ptr<Character> createCharacter() override {std::cout << "=== 戰士工廠創建角色 ===" << std::endl;return std::make_unique<Warrior>(); // 創建戰士}
};// 具體工廠2:法師工廠
class MageFactory : public CharacterFactory {
public:std::unique_ptr<Character> createCharacter() override {std::cout << "=== 法師工廠創建角色 ===" << std::endl;return std::make_unique<Mage>(); // 創建法師}
};// 具體工廠3:弓箭手工廠
class ArcherFactory : public CharacterFactory {
public:std::unique_ptr<Character> createCharacter() override {std::cout << "=== 弓箭手工廠創建角色 ===" << std::endl;return std::make_unique<Archer>(); // 創建弓箭手}
};// 客戶端:游戲角色選擇系統
class GameSystem {
public:// 根據選擇的工廠創建角色并執行操作static void playWithCharacter(CharacterFactory& factory) {auto character = factory.createCharacter(); // 通過工廠獲取角色std::cout << "創建了角色:" << character->getName() << std::endl;// 角色執行戰斗操作character->attack();character->defend();std::cout << std::endl;}
};int main() {// 玩家選擇戰士WarriorFactory warriorFactory;GameSystem::playWithCharacter(warriorFactory);// 玩家選擇法師MageFactory mageFactory;GameSystem::playWithCharacter(mageFactory);// 玩家選擇弓箭手ArcherFactory archerFactory;GameSystem::playWithCharacter(archerFactory);// 如需添加新角色(如刺客),只需新增:// 1. Assassin類(實現Character接口)// 2. AssassinFactory類(實現CharacterFactory接口)// 無需修改現有代碼,符合開閉原則return 0;
}
c語言的工廠方法模式
????????我們在用keil5開發單片機程序時候,可以也學著這種方法去開發。這樣結構清晰。具體就是將共有的部分抽離出來,做結構體。功能的實現封裝函數指針,放入結構體中。這樣子對于多模塊的使用,以及后續拓展都有很好的便捷性。
給出示例
#include <stdio.h>
#include <stdlib.h>
#include <string.h>// -------------------------- 外設抽象產品 --------------------------
// 外設抽象接口(相當于抽象類)
typedef struct Peripheral {void (*enable)(struct Peripheral*); // 使能設備void (*disable)(struct Peripheral*); // 禁用設備void (*set_param)(struct Peripheral*, int param, int value); // 設置參數void (*destroy)(struct Peripheral*); // 銷毀資源const char* name; // 設備名稱// 可以添加通用屬性,如設備地址、狀態等int address;int status; // 0: 禁用, 1: 使能
} Peripheral;// -------------------------- 具體產品實現(電機) --------------------------
// 電機特有參數定義
#define MOTOR_PARAM_SPEED 1 // 速度參數
#define MOTOR_PARAM_DIRECTION 2 // 方向參數// 電機使能
static void motor_enable(Peripheral* dev) {dev->status = 1;printf("[%s] 已使能 (地址: 0x%02X) - 開始運轉\n", dev->name, dev->address);
}// 電機禁用
static void motor_disable(Peripheral* dev) {dev->status = 0;printf("[%s] 已禁用 (地址: 0x%02X) - 停止運轉\n", dev->name, dev->address);
}// 電機參數設置(速度0-100,方向0-1)
static void motor_set_param(Peripheral* dev, int param, int value) {if (dev->status != 1) {printf("[%s] 未使能,無法設置參數\n", dev->name);return;}switch(param) {case MOTOR_PARAM_SPEED:printf("[%s] 設置速度: %d%%\n", dev->name, value);break;case MOTOR_PARAM_DIRECTION:printf("[%s] 設置方向: %s\n", dev->name, value ? "正向" : "反向");break;default:printf("[%s] 未知參數: %d\n", dev->name, param);}
}// 電機資源銷毀
static void motor_destroy(Peripheral* dev) {printf("[%s] 銷毀資源 (地址: 0x%02X)\n", dev->name, dev->address);free(dev);
}// 創建電機設備
Peripheral* create_motor(int address) {Peripheral* motor = (Peripheral*)malloc(sizeof(Peripheral));if (!motor) return NULL;motor->name = "直流電機";motor->address = address;motor->status = 0; // 初始禁用狀態motor->enable = motor_enable;motor->disable = motor_disable;motor->set_param = motor_set_param;motor->destroy = motor_destroy;return motor;
}// -------------------------- 具體產品實現(顯示屏) --------------------------
// 顯示屏特有參數定義
#define DISPLAY_PARAM_BRIGHTNESS 1 // 亮度參數
#define DISPLAY_PARAM_CONTRAST 2 // 對比度參數// 顯示屏使能
static void display_enable(Peripheral* dev) {dev->status = 1;printf("[%s] 已使能 (地址: 0x%02X) - 屏幕點亮\n", dev->name, dev->address);
}// 顯示屏禁用
static void display_disable(Peripheral* dev) {dev->status = 0;printf("[%s] 已禁用 (地址: 0x%02X) - 屏幕關閉\n", dev->name, dev->address);
}// 顯示屏參數設置(亮度0-100,對比度0-100)
static void display_set_param(Peripheral* dev, int param, int value) {if (dev->status != 1) {printf("[%s] 未使能,無法設置參數\n", dev->name);return;}switch(param) {case DISPLAY_PARAM_BRIGHTNESS:printf("[%s] 設置亮度: %d%%\n", dev->name, value);break;case DISPLAY_PARAM_CONTRAST:printf("[%s] 設置對比度: %d%%\n", dev->name, value);break;default:printf("[%s] 未知參數: %d\n", dev->name, param);}
}// 顯示屏資源銷毀
static void display_destroy(Peripheral* dev) {printf("[%s] 銷毀資源 (地址: 0x%02X)\n", dev->name, dev->address);free(dev);
}// 創建顯示屏設備
Peripheral* create_display(int address) {Peripheral* display = (Peripheral*)malloc(sizeof(Peripheral));if (!display) return NULL;display->name = "OLED顯示屏";display->address = address;display->status = 0; // 初始禁用狀態display->enable = display_enable;display->disable = display_disable;display->set_param = display_set_param;display->destroy = display_destroy;return display;
}// -------------------------- 具體產品實現(繼電器) --------------------------
// 繼電器特有參數定義
#define RELAY_PARAM_DELAY 1 // 延遲參數(毫秒)// 繼電器使能
static void relay_enable(Peripheral* dev) {dev->status = 1;printf("[%s] 已使能 (地址: 0x%02X) - 開關閉合\n", dev->name, dev->address);
}// 繼電器禁用
static void relay_disable(Peripheral* dev) {dev->status = 0;printf("[%s] 已禁用 (地址: 0x%02X) - 開關斷開\n", dev->name, dev->address);
}// 繼電器參數設置(延遲時間)
static void relay_set_param(Peripheral* dev, int param, int value) {if (dev->status != 1) {printf("[%s] 未使能,無法設置參數\n", dev->name);return;}switch(param) {case RELAY_PARAM_DELAY:printf("[%s] 設置延遲: %d毫秒\n", dev->name, value);break;default:printf("[%s] 未知參數: %d\n", dev->name, param);}
}// 繼電器資源銷毀
static void relay_destroy(Peripheral* dev) {printf("[%s] 銷毀資源 (地址: 0x%02X)\n", dev->name, dev->address);free(dev);
}// 創建繼電器設備
Peripheral* create_relay(int address) {Peripheral* relay = (Peripheral*)malloc(sizeof(Peripheral));if (!relay) return NULL;relay->name = "電磁繼電器";relay->address = address;relay->status = 0; // 初始禁用狀態relay->enable = relay_enable;relay->disable = relay_disable;relay->set_param = relay_set_param;relay->destroy = relay_destroy;return relay;
}// -------------------------- 外設工廠定義 --------------------------
// 外設類型枚舉
typedef enum {PERIPHERAL_MOTOR, // 電機PERIPHERAL_DISPLAY, // 顯示屏PERIPHERAL_RELAY // 繼電器
} PeripheralType;// 外設工廠:根據類型和地址創建對應外設
Peripheral* peripheral_factory_create(PeripheralType type, int address) {switch(type) {case PERIPHERAL_MOTOR:return create_motor(address);case PERIPHERAL_DISPLAY:return create_display(address);case PERIPHERAL_RELAY:return create_relay(address);default:printf("未知外設類型: %d\n", type);return NULL;}
}// -------------------------- 客戶端示例(工業控制邏輯) --------------------------
// 外設控制通用函數(體現多態性)
void peripheral_operate(Peripheral* dev) {// 使能設備dev->enable(dev);// 設置設備特定參數(不同設備參數含義不同,但調用方式統一)if (strcmp(dev->name, "直流電機") == 0) {dev->set_param(dev, MOTOR_PARAM_SPEED, 70);dev->set_param(dev, MOTOR_PARAM_DIRECTION, 1);} else if (strcmp(dev->name, "OLED顯示屏") == 0) {dev->set_param(dev, DISPLAY_PARAM_BRIGHTNESS, 80);dev->set_param(dev, DISPLAY_PARAM_CONTRAST, 50);} else if (strcmp(dev->name, "電磁繼電器") == 0) {dev->set_param(dev, RELAY_PARAM_DELAY, 100);}// 禁用設備dev->disable(dev);
}int main() {// 通過工廠創建不同外設(地址用于區分硬件接口)Peripheral* motor = peripheral_factory_create(PERIPHERAL_MOTOR, 0x01);Peripheral* display = peripheral_factory_create(PERIPHERAL_DISPLAY, 0x02);Peripheral* relay = peripheral_factory_create(PERIPHERAL_RELAY, 0x03);if (!motor || !display || !relay) {printf("設備創建失敗\n");return -1;}// 統一操作不同外設printf("=== 電機操作 ===\n");peripheral_operate(motor);printf("\n=== 顯示屏操作 ===\n");peripheral_operate(display);printf("\n=== 繼電器操作 ===\n");peripheral_operate(relay);// 銷毀資源motor->destroy(motor);display->destroy(display);relay->destroy(relay);return 0;
}