• 正文
  • 相關推薦
申請入駐 產業(yè)圖譜

嵌入式編程模型 | 抽象工廠模式

4小時前
86
加入交流群
掃碼加入
獲取工程師必備禮包
參與熱點資訊討論

一、抽象工廠模式

抽象工廠模式(Abstract Factory Pattern)是一種創(chuàng)建型設計模式,它提供一個接口用于創(chuàng)建相關或依賴對象的家族,而無需指定它們的具體類。

在需要高兼容性的嵌入式系統(tǒng)中,抽象工廠模式能顯著降低多平臺適配成本,確保硬件組件間的兼容性,是構建可移植嵌入式框架的核心模式。

上一篇我們分享了:嵌入式編程模型 | 簡單工廠模式

抽象工廠模式(Abstract Factory Pattern)與簡單工廠模式有很多相似之處。我們先做個對比:

特性 簡單工廠模式 抽象工廠模式
嵌入式應用 單一設備驅動管理 整套硬件平臺適配
適用場景 產品類型少且變化不頻繁 需要創(chuàng)建多個相關產品的系統(tǒng)
抽象級別 產品級別抽象 工廠級別抽象
創(chuàng)建對象 單個產品 產品家族(多個相關產品)
工廠類型 單一工廠類 抽象工廠+多個具體工廠實現類
擴展性 添加新產品需修改工廠類 添加新產品族只需新增工廠類

簡單工廠模式適用于產品類型少且變化不頻繁的場景。如嵌入式中對單一設備驅動管理,比如管理LCD驅動:

抽象工廠模式適用于需要創(chuàng)建多個相關產品的系統(tǒng)。如嵌入式中對整個硬件平臺的管理。

抽象工廠模式的核心包含四個關鍵部分:

    抽象工廠(Abstract Factory):聲明創(chuàng)建一系列產品的方法。具體工廠(Concrete Factory):實現抽象工廠的方法,創(chuàng)建具體產品。抽象產品(Abstract Product):聲明產品接口。具體產品(Concrete Product):實現抽象產品接口,定義具體產品。

其中,第2~4點就是簡單工廠模式的要點。即簡單工廠模式加上第1點的抽象工廠這個要點就構成了抽象工廠模式。

二、嵌入式:多平臺硬件抽象層

設備需要支持不同平臺(STM32/ESP32等),每個平臺有兼容的輸入、輸出驅動。

1、代碼

C語言版本:

#include?<stdio.h>
#include?<stdbool.h>

// 抽象產品(Abstract Product)
typedefstruct?{
? ??void?(*Init)(void);
? ??void?(*Draw)(int?x,?int?y);
} DisplayDriver;

typedefstruct?{
? ??void?(*Init)(void);
? ??bool?(*ReadButton)(void);
} InputDriver;

// 具體產品實現 - STM32平臺
void?stm32_disp_init(void)?{
? ??printf("STM32 Display Initializedn");
}

void?stm32_draw(int?x,?int?y)?{
? ??printf("STM32 Drawing at (%d, %d)n", x, y);
}

void?stm32_button_init(void)?{
? ??printf("STM32 Button Initializedn");
}

bool?stm32_read_button(void)?{
? ??printf("STM32 Button Readn");
? ??returntrue;?// 模擬按下狀態(tài)
}

// 具體產品實現 - ESP32平臺
void?esp32_disp_init(void)?{
? ??printf("ESP32 Display Initializedn");
}

void?esp32_draw(int?x,?int?y)?{
? ??printf("ESP32 Drawing at (%d, %d)n", x, y);
}

void?esp32_button_init(void)?{
? ??printf("ESP32 Button Initializedn");
}

bool?esp32_read_button(void)?{
? ??printf("ESP32 Button Readn");
? ??returnfalse;?// 模擬未按下狀態(tài)
}

// 抽象工廠(Abstract Factory)
typedefstruct?{
? ? DisplayDriver display;
? ? InputDriver input;
} HWPlatform;

// 具體工廠(Concrete Factory) - STM32平臺
const?HWPlatform stm32_platform = {
? ? {stm32_disp_init, stm32_draw},
? ? {stm32_button_init, stm32_read_button}
};

// 具體工廠(Concrete Factory) - ESP32平臺
const?HWPlatform esp32_platform = {
? ? {esp32_disp_init, esp32_draw},
? ? {esp32_button_init, esp32_read_button}
};

int?main()?{
? ??// 選擇平臺 - 通過定義USE_STM32宏來選擇
? ??#if?defined(USE_STM32)
? ? ? ??constchar* platform_name =?"STM32";
? ? ? ??const?HWPlatform* platform = &stm32_platform;
? ??#else
? ? ? ??constchar* platform_name =?"ESP32";
? ? ? ??const?HWPlatform* platform = &esp32_platform;
? ??#endif
? ??
? ??printf("Running on %s platformn", platform_name);
? ??
? ??// 初始化顯示
? ? platform->display.Init();
? ??
? ??// 初始化輸入
? ? platform->input.Init();
? ??
? ??// 繪制圖形
? ? platform->display.Draw(10,?20);
? ? platform->display.Draw(30,?40);
? ??
? ??// 讀取按鈕狀態(tài)
? ??bool?buttonState = platform->input.ReadButton();
? ??printf("Button state: %sn", buttonState ??"PRESSED"?:?"RELEASED");
? ??
? ??return0;
}

C ++版本:

#include?<iostream>
#include?<cstdint>

// 抽象產品接口
struct?DisplayDriver?{
? ??void?(*Init)(void);
? ??void?(*Draw)(int?x,?int?y);
};

struct?InputDriver?{
? ??void?(*Init)(void);
? ??bool?(*ReadButton)(void);
};

// 具體產品實現 - STM32平臺
namespace?STM32 {
? ??void?DisplayInit()?{
? ? ? ??std::cout?<<?"[STM32] Display initializedn";
? ? }
? ??
? ??void?DisplayDraw(int?x,?int?y)?{
? ? ? ??std::cout?<<?"[STM32] Drawing at ("?<< x <<?", "?<< y <<?")n";
? ? }
? ??
? ??void?InputInit()?{
? ? ? ??std::cout?<<?"[STM32] Input initializedn";
? ? }
? ??
? ??bool?InputReadButton()?{
? ? ? ??std::cout?<<?"[STM32] Reading buttonn";
? ? ? ??returntrue;?// 模擬按鈕被按下
? ? }
}

// 具體產品實現 - ESP32平臺
namespace?ESP32 {
? ??void?DisplayInit()?{
? ? ? ??std::cout?<<?"[ESP32] Display initializedn";
? ? }
? ??
? ??void?DisplayDraw(int?x,?int?y)?{
? ? ? ??std::cout?<<?"[ESP32] Drawing at ("?<< x <<?", "?<< y <<?")n";
? ? }
? ??
? ??void?InputInit()?{
? ? ? ??std::cout?<<?"[ESP32] Input initializedn";
? ? }
? ??
? ??bool?InputReadButton()?{
? ? ? ??std::cout?<<?"[ESP32] Reading buttonn";
? ? ? ??returnfalse;?// 模擬按鈕未被按下
? ? }
}

// 抽象工廠
class?HWPlatform?{
public:
? ??const?DisplayDriver&?GetDisplayDriver()?const?{?return?display; }
? ??const?InputDriver&?GetInputDriver()?const?{?return?input; }
? ??
? ??virtual?void?PrintPlatformInfo()?const?{
? ? ? ??std::cout?<<?"Generic Hardware Platformn";
? ? }
? ??
protected:
? ? DisplayDriver display;
? ? InputDriver input;
};

// 具體工廠 - STM32平臺
class?STM32Platform?:public?HWPlatform {
public:
? ? STM32Platform() {
? ? ? ? display.Init = STM32::DisplayInit;
? ? ? ? display.Draw = STM32::DisplayDraw;
? ? ? ? input.Init = STM32::InputInit;
? ? ? ? input.ReadButton = STM32::InputReadButton;
? ? }
? ??
? ??void?PrintPlatformInfo()?const?override?{
? ? ? ??std::cout?<<?"n=== STM32 Hardware Platform ===n";
? ? }
};

// 具體工廠 - ESP32平臺
class?ESP32Platform?:public?HWPlatform {
public:
? ? ESP32Platform() {
? ? ? ? display.Init = ESP32::DisplayInit;
? ? ? ? display.Draw = ESP32::DisplayDraw;
? ? ? ? input.Init = ESP32::InputInit;
? ? ? ? input.ReadButton = ESP32::InputReadButton;
? ? }
? ??
? ??void?PrintPlatformInfo()?const?override?{
? ? ? ??std::cout?<<?"n=== ESP32 Hardware Platform ===n";
? ? }
};

// 使用示例
int?main()?{
? ??std::cout?<<?"=== Embedded Hardware Platform Demo ===n";
? ??
? ??// 平臺選擇
? ??#if?defined(USE_STM32)
? ? ? ? STM32Platform platform;
? ? ? ??std::cout?<<?"Selected platform: STM32n";
? ??#else
? ? ? ? ESP32Platform platform;
? ? ? ??std::cout?<<?"Selected platform: ESP32n";
? ??#endif

? ??// 打印平臺信息
? ? platform.PrintPlatformInfo();
? ??
? ??// 初始化硬件
? ??std::cout?<<?"nInitializing hardware...n";
? ? platform.GetDisplayDriver().Init();
? ? platform.GetInputDriver().Init();
? ??
? ??// 使用顯示驅動
? ??std::cout?<<?"nDrawing on display...n";
? ? platform.GetDisplayDriver().Draw(5,?10);
? ? platform.GetDisplayDriver().Draw(15,?25);
? ? platform.GetDisplayDriver().Draw(30,?40);
? ??
? ??// 讀取輸入狀態(tài)
? ??std::cout?<<?"nReading input...n";
? ??bool?buttonState = platform.GetInputDriver().ReadButton();
? ??std::cout?<<?"Button state: "?<< (buttonState ??"PRESSED"?:?"RELEASED") <<?"n";
? ??
? ??return0;
}

2、優(yōu)缺點分析

(1)優(yōu)點

① 符合開閉原則

開閉原則?(The Open/Closed Principle, OCP) :軟件中的對象(類,模塊,函數等等)應該對于擴展是開放的,但是對于修改是封閉的。

    • 初始支持:STM32和ESP32新增平臺:添加Nordic nRF52支持

      • 新增

NRF52Platform

      • 工廠類新增nRF52顯示/輸入驅動

無需修改

    • 現有STM32/ESP32代碼

② 接口統(tǒng)一化

// 統(tǒng)一的硬件操作接口
platform->display.Init();
platform->input.Init();
platform->display.Draw(10, 20);
platform->display.Draw(30, 40);
bool buttonState = platform->input.ReadButton();

③ 平臺無關性設計

    業(yè)務邏輯與硬件解耦代碼復用率高,減少平臺移植工作量(新平臺只需實現具體工廠和產品)
(2)缺點

① 擴展新產品困難

例如:

    初始設計:顯示+輸入新增需求:攝像頭模塊修改成本:

    • 修改所有3個平臺工廠類添加3個攝像頭驅動實現更新所有測試用例

三、總結:何時選擇抽象工廠

相關推薦

登錄即可解鎖
  • 海量技術文章
  • 設計資源下載
  • 產業(yè)鏈客戶資源
  • 寫文章/發(fā)需求
立即登錄

本公眾號專注于嵌入式技術,包括但不限于C/C++、嵌入式、物聯網、Linux等編程學習筆記,同時,公眾號內包含大量的學習資源。歡迎關注,一同交流學習,共同進步!