依賴倒置 DIP、依賴注入 DI、控制反轉 IoC 和工廠模式

1. 依賴倒置

依賴倒置原則(Dependency Inversion Principle, DIP)是 SOLID 原則中的一項,其核心思想是通過抽象解耦高層模塊和低層模塊,使二者都依賴于抽象而非具體實現

依賴反轉/倒置的體現:傳統依賴方向是高層模塊直接調用低層模塊,在源碼級別上高層模塊依賴低層細節模塊。而 DIP 通過抽象反轉這種依賴關系,使低層模塊的實現在源碼級別上依賴高層定義的抽象(視為高層模塊的一部分)。

1.1 依賴倒置原則的核心

  1. 高層模塊不直接依賴低層模塊,二者都應依賴抽象(接口或抽象類,接口由高層模塊定義,視為高層模塊的一部分)。

  2. 抽象不依賴細節,細節(具體實現)應依賴抽象。

1.2 依賴倒置指導方針

  • 變量不可以持有具體類的引用——改用工廠,避免直接使用 new 持有具體類的引用(new 具體類的操作都封裝到工廠中)

  • 不要讓類派生自具體類——派生自抽象類或接口,這樣就不依賴具體類了

  • 不要覆蓋基類中已經實現的方法——如果這樣,說明不是一個真正適合被繼承的抽象

1.3 示例

場景

  • 高層模塊?ReportGenerator?需要生成報告,依賴數據獲取功能。

  • 低層模塊?MySQLDatabase?和?SQLiteDatabase?提供具體的數據操作。

傳統實現(未遵循 DIP)

// 低層模塊:直接依賴具體實現
class MySQLDatabase {
public:void connect() { /* MySQL 連接邏輯 */ }std::string fetchData() { return "MySQL 數據"; }
};// 高層模塊直接依賴低層具體類
class ReportGenerator {
private:MySQLDatabase db;  // 直接依賴具體實現
public:void generateReport() {db.connect();auto data = db.fetchData();std::cout << "報告數據: " << data << std::endl;}
};

問題ReportGenerator?直接依賴?MySQLDatabase,更換數據庫(如改用 SQLite)需修改高層代碼。

遵循 DIP 的實現

1、定義抽象接口

class Database {
public:virtual ~Database() = default;virtual void connect() = 0;virtual std::string fetchData() = 0;
};

2、低層模塊實現接口

class MySQLDatabase : public Database {
public:void connect() override { /* MySQL 連接邏輯 */ }std::string fetchData() override { return "MySQL 數據"; }
};class SQLiteDatabase : public Database {
public:void connect() override { /* SQLite 連接邏輯 */ }std::string fetchData() override { return "SQLite 數據"; }
};

3、高層模塊依賴抽象

class ReportGenerator {
private:Database& db;  // 依賴抽象接口
public:ReportGenerator(Database& database) : db(database) {}  // 依賴注入void generateReport() {db.connect();auto data = db.fetchData();std::cout << "報告數據: " << data << std::endl;}
};

class ReportGenerator {
private:Database& db;  // 依賴抽象接口
public:ReportGenerator(Database& database) : db(database) {}  // 依賴注入void generateReport() {db.connect();auto data = db.fetchData();std::cout << "報告數據: " << data << std::endl;}
};

4、使用示例

int main() {MySQLDatabase mysqlDb;SQLiteDatabase sqliteDb;ReportGenerator report1(mysqlDb);   // 使用 MySQLreport1.generateReport();ReportGenerator report2(sqliteDb);  // 使用 SQLitereport2.generateReport();return 0;
}

1.4 依賴倒置優勢

  • 解耦:高層模塊不依賴低層具體實現,可靈活替換數據庫(如新增?MongoDB?只需實現?Database?接口)。

  • 可維護性:修改低層代碼(如優化?MySQLDatabase)不影響高層模塊。

  • 可測試性:可通過 Mock 對象(實現?Database?接口)輕松測試?ReportGenerator

1.5 依賴倒置小結

依賴倒置原則通過抽象解耦模塊,使依賴關系從“高層 → 低層”變為“高層 → 抽象 ← 低層”,從而提升系統的靈活性和可維護性。在 C++ 中,可通過抽象類(接口)和依賴注入(如構造函數傳入接口指針/引用)實現這一原則。

2. 依賴注入 DI

依賴注入(Dependency Injection, DI)是一種將對象依賴關系的外部化技術,其核心思想是:對象不直接創建或管理自己的依賴,而是由外部(調用者或框架)提供依賴的實例。通過這種方式,代碼的耦合度降低,靈活性和可測試性顯著提高。

2.1 依賴注入的本質

1、控制反轉(IoC)

依賴注入是控制反轉的一種實現方式。傳統代碼中,對象自己控制依賴的創建(如?new?一個具體類),而依賴注入將這一控制權交給外部,實現“依賴被注入到對象中”。

2、依賴抽象而非實現

依賴注入通常結合接口或抽象類使用,確保對象依賴的是抽象,而非具體實現(符合依賴倒置原則)。

2.2 依賴注入的三種方式

1.?構造函數注入(最常用)

通過構造函數傳遞依賴,確保對象在創建時即具備完整依賴。

class NotificationService {
private:MessageSender& sender;  // 依賴抽象接口
public:NotificationService(MessageSender& sender) : sender(sender) {}  // 構造函數注入void sendMessage(const std::string& msg) {sender.send(msg);}
};

2.?屬性注入(Setter 注入)

通過公開的成員屬性或 Setter 方法動態設置依賴。

class NotificationService {
public:void setSender(MessageSender& sender) {  // Setter 注入this->sender = &sender;}
private:MessageSender* sender;
};

3.?方法注入

通過方法參數傳遞依賴,適用于臨時或局部依賴。

class NotificationService {
public:void sendMessage(MessageSender& sender, const std::string& msg) {  // 方法注入sender.send(msg);}
};

2.3 為什么需要依賴注入?

1.?解耦與可維護性

  • 傳統代碼:對象內部直接創建依賴,導致緊耦合。

class UserService {
private:
MySQLDatabase db; // 直接依賴具體類
};


若需改用 `SQLiteDatabase`,必須修改 `UserService` 的代碼。- **依賴注入**:通過接口解耦,僅需注入不同實現。```cpp
class UserService {
private:Database& db;  // 依賴抽象
public:UserService(Database& db) : db(db) {}
};

2.?可測試性

  • 依賴注入允許在測試時替換為 Mock 對象。

class MockDatabase : public Database { /* 模擬實現 */ };TEST(UserServiceTest) {MockDatabase mockDb;UserService service(mockDb);  // 注入 Mock 對象// 執行測試...
}

3.?擴展性
  • 新增功能時,只需實現新依賴并注入,無需修改現有代碼。

class MongoDB : public Database { /* 新數據庫實現 */ };MongoDB mongoDb;
UserService service(mongoDb);  // 直接注入新依賴

2.4 C++ 依賴注入的實踐技巧

1.?使用智能指針管理生命周期

避免裸指針導致的內存泄漏,使用?std::shared_ptr?或?std::unique_ptr

class NotificationService {
private:std::shared_ptr<MessageSender> sender;  // 智能指針管理依賴
public:NotificationService(std::shared_ptr<MessageSender> sender) : sender(sender) {}
};

2.?結合工廠模式

通過工廠類集中管理依賴的創建邏輯。

class SenderFactory {
public:static std::shared_ptr<MessageSender> createSender(const std::string& type) {if (type == "email") return std::make_shared<EmailSender>();else return std::make_shared<SmsSender>();}
};// 使用工廠創建依賴
auto sender = SenderFactory::createSender("email");
NotificationService service(sender);

3.?依賴注入容器(IoC Container)

在復雜項目中,使用容器自動管理依賴關系(如 Boost.DI)。

#include <boost/di.hpp>
namespace di = boost::di;// 定義接口和實現
class Database { /* ... */ };
class MySQLDatabase : public Database { /* ... */ };// 配置容器
auto injector = di::make_injector(di::bind<Database>().to<MySQLDatabase>()
);// 自動注入依賴
class UserService {
public:UserService(Database& db) { /* ... */ }
};
UserService service = injector.create<UserService>();

2.5 依賴注入的常見誤區

1、依賴注入 ≠ 工廠模式

工廠模式負責創建對象,而依賴注入負責傳遞對象。二者常結合使用,但目的不同。

2、依賴注入 ≠ 必須用框架

即使不用框架(如 Boost.DI),通過構造函數或參數傳遞依賴,也能實現依賴注入。

3、過度注入問題

若一個類需要注入過多依賴(如超過 4 個),可能設計存在問題,需考慮拆分職責。

2.6 依賴注入小結

  • 依賴注入的核心:將依賴的創建和綁定從對象內部轉移到外部。

  • 核心價值:解耦、可測試、可擴展。

C++ 實現關鍵:

通過接口抽象依賴。

使用構造函數/智能指針傳遞依賴。

結合工廠模式或 IoC 容器管理復雜依賴關系。

3. 控制反轉 IoC

IoC(Inversion of Control,控制反轉)?是一種軟件設計原則,其核心思想是將程序流程的控制權從開發者轉移給框架或容器,以降低代碼的耦合度,提高模塊化和可維護性。它是實現依賴倒置原則(DIP)的關鍵機制,也是現代框架(如 Spring、.NET Core)和依賴注入(DI)容器的基礎。

3.1 控制反轉 IoC vs. 依賴注入 DI

  • IoC(控制反轉):廣義的設計原則,表示控制權轉移的范式。其本質是將程序流程的控制權從開發者轉移到框架或容器

  • DI(依賴注入):IoC 的一種具體實現技術,通過外部傳遞依賴。

關系

  • 依賴注入是控制反轉的實現方式之一。

  • 控制反轉還可以通過模板方法、回調(關聯:好萊塢原則)等方式實現。

  • 使用 IoC 容器(如 Boost.DI)自動管理復雜依賴關系。

4. 工廠模式

盡管依賴倒置和依賴注入都強調面向抽象編程,但在實際編碼中仍需創建(new)具體底層組件(ConcreteClass)

工廠模式主要分為三種,嚴格來說包括?簡單工廠模式工廠方法模式?和?抽象工廠模式。以下是它們的核心區別、適用場景及 C++ 示例:

4.1 簡單工廠模式(Simple Factory)

有時候簡單工廠不被視為正式的設計模式,而是一個編程習慣。

核心思想

  • 通過一個工廠類,根據傳入的參數決定創建哪種具體產品對象。

  • 不符合開閉原則(新增產品需修改工廠類邏輯)。

適用場景

  • 產品類型較少且創建邏輯簡單。

  • 不需要頻繁擴展新類型。

C++ 示例

// 抽象產品
class Shape {
public:virtual void draw() = 0;virtual ~Shape() = default;
};// 具體產品
class Circle : public Shape {
public:void draw() override { std::cout << "畫一個圓形" << std::endl; }
};class Square : public Shape {
public:void draw() override { std::cout << "畫一個正方形" << std::endl; }
};// 簡單工廠類
class ShapeFactory {
public:static Shape* createShape(const std::string& type) {if (type == "circle") return new Circle();else if (type == "square") return new Square();else return nullptr;}
};// 使用示例
int main() {Shape* circle = ShapeFactory::createShape("circle");circle->draw();  // 輸出: 畫一個圓形delete circle;return 0;
}

4.2 工廠方法模式(Factory Method)

核心思想
  • 定義一個創建對象的抽象方法,由子類決定實例化哪個類。

  • 符合開閉原則(新增產品只需新增子類工廠)。

適用場景
  • 產品類型可能頻繁擴展。

  • 需要將對象創建延遲到子類。

C++ 示例

// 抽象產品
class Database {
public:virtual void connect() = 0;virtual ~Database() = default;
};// 具體產品
class MySQL : public Database {
public:void connect() override { std::cout << "連接到 MySQL" << std::endl; }
};class PostgreSQL : public Database {
public:void connect() override { std::cout << "連接到 PostgreSQL" << std::endl; }
};// 抽象工廠
class DatabaseFactory {
public:virtual Database* createDatabase() = 0;virtual ~DatabaseFactory() = default;
};// 具體工廠
class MySQLFactory : public DatabaseFactory {
public:Database* createDatabase() override { return new MySQL(); }
};class PostgreSQLFactory : public DatabaseFactory {
public:Database* createDatabase() override { return new PostgreSQL(); }
};// 使用示例
int main() {DatabaseFactory* factory = new PostgreSQLFactory();Database* db = factory->createDatabase();db->connect();  // 輸出: 連接到 PostgreSQLdelete db;delete factory;return 0;
}

4.3 抽象工廠模式(Abstract Factory)

核心思想
  • 提供一個接口,用于創建相關或依賴對象族,而無需指定具體類。

  • 抽象工廠包含多個工廠方法,每個方法負責創建一個產品族中的對象。

適用場景
  • 需要創建一組相關或依賴的對象(例如 GUI 組件:按鈕、文本框、下拉菜單等)。

  • 系統需要獨立于產品的創建、組合和表示。

C++ 示例

// 抽象產品:按鈕
class Button {
public:virtual void render() = 0;virtual ~Button() = default;
};// 具體產品:Windows 按鈕
class WindowsButton : public Button {
public:void render() override { std::cout << "Windows 風格按鈕" << std::endl; }
};// 具體產品:MacOS 按鈕
class MacOSButton : public Button {
public:void render() override { std::cout << "MacOS 風格按鈕" << std::endl; }
};// 抽象產品:文本框
class TextBox {
public:virtual void display() = 0;virtual ~TextBox() = default;
};// 具體產品:Windows 文本框
class WindowsTextBox : public TextBox {
public:void display() override { std::cout << "Windows 風格文本框" << std::endl; }
};// 具體產品:MacOS 文本框
class MacOSTextBox : public TextBox {
public:void display() override { std::cout << "MacOS 風格文本框" << std::endl; }
};// 抽象工廠
class GUIFactory {
public:virtual Button* createButton() = 0;virtual TextBox* createTextBox() = 0;virtual ~GUIFactory() = default;
};// 具體工廠:Windows 風格組件
class WindowsFactory : public GUIFactory {
public:Button* createButton() override { return new WindowsButton(); }TextBox* createTextBox() override { return new WindowsTextBox(); }
};// 具體工廠:MacOS 風格組件
class MacOSFactory : public GUIFactory {
public:Button* createButton() override { return new MacOSButton(); }TextBox* createTextBox() override { return new MacOSTextBox(); }
};// 使用示例
int main() {GUIFactory* factory = new MacOSFactory();Button* button = factory->createButton();button->render();  // 輸出: MacOS 風格按鈕TextBox* textBox = factory->createTextBox();textBox->display(); // 輸出: MacOS 風格文本框delete button;delete textBox;delete factory;return 0;
}

4.4 三種工廠模式對比

4.5 工廠模式小結

  • 簡單工廠:適合簡單場景,但違背開閉原則。

  • 工廠方法:解決單一產品的擴展問題。

  • 抽象工廠:解決多產品族的創建問題,強調產品之間的關聯性。

根據需求選擇合適模式:若產品單一且可能擴展,用工廠方法;若需創建一組關聯對象,用抽象工廠;若產品類型固定且簡單,用簡單工廠。

5. 總結

依賴倒置(DIP)、依賴注入(DI)、控制反轉(IoC)和工廠模式是軟件設計中緊密相關的概念,它們共同服務于代碼的解耦和可維護性。

5.1 關聯

  • 依賴倒置原則(Dependency Inversion Principle, DIP):高層模塊不依賴低層模塊,兩者都依賴抽象(接口或抽象類)。該思想指導工廠模式、DI 和 IoC 的設計方向。

  • 控制反轉(Inversion of Control, IoC):將對象的創建和生命周期管理權從程序內部轉移給外部容器(如框架)。例如:依賴由外部容器(如工廠或框架)創建并注入,而不是直接創建依賴。工廠模式和依賴注入 DI 是實現 IoC 的具體方式。

  • 依賴注入(Dependency Injection, DI):通過構造函數、Setter 或接口,將依賴對象被動傳遞給使用方。是實現 IoC 的具體技術手段。工廠模式常用于生成這些依賴對象。

  • 工廠模式(Factory Pattern):封裝具體對象創建邏輯,通過工廠類統一創建對象。是實現 IoC 的手段之一,隱藏實例化細節,支持 DIP 和 DI。是依賴注入 DI 和控制反轉 IoC 的底層支撐。

四者共同目標是解耦代碼,提升擴展性和可維護性。

5.2 示例全鏈路

// 1. 遵循 DIP:定義抽象接口
class IStorage { /* ... */ };// 2. 具體實現
class DatabaseStorage : public IStorage { /* ... */ };// 3. 工廠模式:封裝對象創建
class StorageFactory {
public:static IStorage* createStorage() { return new DatabaseStorage(); }
};// 4. 依賴注入:通過構造函數傳遞對象
class UserService {
private:IStorage* storage;
public:UserService(IStorage* storage) : storage(storage) {}
};// 5. 控制反轉:由工廠創建依賴,而非 UserService 內部創建
int main() {IStorage* storage = StorageFactory::createStorage();UserService userService(storage); // DI 注入userService.saveUser();delete storage;return 0;
}

文章轉載自:Zijian/TENG

原文鏈接:依賴倒置 DIP、依賴注入 DI、控制反轉 IoC 和工廠模式 - Zijian/TENG - 博客園

體驗地址:引邁 - JNPF快速開發平臺_低代碼開發平臺_零代碼開發平臺_流程設計器_表單引擎_工作流引擎_軟件架構

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

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

相關文章

UnitTest框架管理測試用例——python自動化測試

UnitTest框架 UnitTest是Python自帶一個單元測試框架&#xff0c;常用它來做單元測試。 注意:對于測試來說&#xff0c;UnitTest框架的作用是 自動化腳本(用例代碼)執行框架————(使用UnitTest框架來管理 運行多個測試用例的) 為什么使用UnitTest框架 能夠組織多個用例去執…

Vue 過濾器深度解析與應用實踐

文章目錄 1. 過濾器概述1.1 核心概念1.2 過濾器生命周期 2. 過濾器基礎2.1 過濾器定義2.2 過濾器使用 3. 過濾器高級用法3.1 鏈式調用3.2 參數傳遞3.3 動態過濾器 4. 過濾器應用場景4.1 文本格式化4.2 數字處理4.3 數據過濾 5. 性能優化與調試5.1 性能優化策略5.2 調試技巧 6. …

ngx_http_module_t

定義在 src\http\ngx_http_config.h typedef struct {ngx_int_t (*preconfiguration)(ngx_conf_t *cf);ngx_int_t (*postconfiguration)(ngx_conf_t *cf);void *(*create_main_conf)(ngx_conf_t *cf);char *(*init_main_conf)(ngx_conf_t *cf, void *conf);…

每日定投40刀BTC(9)20250312 - 20250315

定投截圖 區塊鏈相關新聞 BTC價格一度跌破8萬美元 3月14日&#xff0c;BTC價格盤中跌破8萬美元&#xff0c;最低報79,954.60美元&#xff0c;日內下跌1.34%&#xff0c;市場情緒一度轉為謹慎 BTC價格波動背后的原因 經濟環境變化、市場情緒波動以及政策監管動態是導致BTC價…

Matlab 汽車二自由度轉彎模型

1、內容簡介 Matlab 187-汽車二自由度轉彎模型 可以交流、咨詢、答疑 2、內容說明 略 摘 要 本文前一部分提出了側偏角和橫擺角速度作為參數。描述了車輛運動的運動狀態&#xff0c;其中文中使用的參考模型是二自由度汽車模型。汽車速度被認為是建立基于H.B.Pacejka的輪胎模…

CentOS 6 YUM源切換成國內yum源

由于 CentOS 6 已于 2020 年 11 月進入 EOL&#xff08;End of Life&#xff09;&#xff0c;官方軟件源已不再提供更新&#xff0c;因此你可能會遇到 yum makecache 命令失敗的問題。以下是解決該問題的詳細步驟&#xff1a; ### 解決方案 1. **備份原有 yum 源文件** bash …

Leetcode 3483. Unique 3-Digit Even Numbers

Leetcode 3483. Unique 3-Digit Even Numbers 1. 解題思路2. 代碼實現 題目鏈接&#xff1a;3483. Unique 3-Digit Even Numbers 1. 解題思路 這一題其實是一個easy的題目&#xff0c;因為限制條件有限&#xff0c;最暴力的方法就是直接遍歷一下100到999的全部數字&#xff…

《基于深度學習的高分衛星圖像配準模型研發與應用》開題報告

目錄 1. 選題的背景和意義 1.1 選題的背景 1.2 國內外研究現狀 1.3 發展趨勢 2&#xff0e;研究的基本內容 2.1 主要研究內容 &#xff08;1&#xff09;訓練與測試數據集構建 &#xff08;2&#xff09;基于深度學習的高精度衛星影像配準模型 &#xff08;3&#xff0…

【Python 算法零基礎 1.線性枚舉】

我裝作漠視一切&#xff0c;以為這樣就可以不在乎 —— 25.3.17 一、線性枚舉的基本概念 1.時間復雜度 線性枚舉的時間復雜度為 O(nm)&#xff0c;其中 n是線性表的長度。m 是每次操作的量級&#xff0c;對于求最大值和求和來說&#xff0c;因為操作比較簡單&#xff0c;所以 …

前端性能優化回答思路

前端性能優化是面試中經常涉及的一個話題&#xff0c;面試官通常希望了解你在實際項目中如何處理性能瓶頸&#xff0c;如何識別和優化性能問題。以下是一些前端性能優化的常見問題以及你可以用來回答的思路&#xff1a; 如何提升頁面加載速度&#xff1f; 回答思路&#xff1…

02-Canvas-fabric.ActiveSelection

fabric.ActiveSelection fabric.ActiveSelection 用于表示當前選中的多個對象&#xff08;即多選狀態&#xff09;。 當用戶在畫布上選擇多個對象時&#xff0c;Fabric.js 會自動將這些對象包裝在fabric.ActiveSelection 實例中&#xff0c;以便統一操作&#xff08;如移動、縮…

Leetcode——151.反轉字符串中的單詞

題解一 思路 最開始的想法是把一個字符串分為字符串數組&#xff0c;但是不知道一共有幾個單詞&#xff08;當時沒想起來split()&#xff09;&#xff0c;所以選擇了用ArrayList儲存字符串&#xff0c;在輸出時沒有考慮ArrayList可以存儲空字符串&#xff0c;所以最開始的輸出…

Oracle檢索數據

一、Oracle用戶模式與模式 對象 1.概念 模式就是數據庫對象的集合&#xff0c;數據庫對象包括表、函數、索引、視圖、過程。 2.示例模式scott SQL> select table_name from user_tables;TABLE_NAME ------------------------------------------------------------------…

Java學習------static、final、this、super關鍵字

1. static關鍵字 static修飾的變量叫做靜態變量。當所有對象的某個屬性的值是相同的&#xff0c;建議將該屬性定義為靜態變量&#xff0c;來節省內存的開銷。靜態變量在類加載時初始化&#xff0c;存儲在堆中。static修飾的方法叫做靜態方法。所有靜態變量和靜態方法&#xff…

一個簡單的 **猜數字游戲** 的 C 語言例程

一個簡單的 猜數字游戲 的 C 語言例程&#xff0c;代碼包含詳細注釋&#xff0c;適合學習和練習基礎語法&#xff1a; #include <stdio.h> #include <stdlib.h> #include <time.h> // 用于生成隨機數種子int main() {int target, guess, attempts 0;srand…

Keepalived 多主模型與 LVS 高可用

一.Keepalived多主模型 Keepalived多主模型概念 如上圖&#xff0c;keepalived主從架構性能損耗較嚴重&#xff0c;如果業務分類明確&#xff0c;則可以配置keepalived多主模型降低損耗&#xff0c;兩臺keepalived互為主備&#xff0c;如&#xff1a;訂單業務走keepalived1&am…

RISCV虛擬化環境搭建

概要 本文記搭建 RISCV 虛擬化環境的流程。 整體架構 我們使用 QEMU 來模擬 RISCV 的各種硬件擴展環境&#xff0c;通過 QEMU 啟動 Ubuntu 作為我們的 Host 來在 Host 之中通過 KVMTOOL 來運行 Guest&#xff0c;學習 RISCV 的虛擬化。 目前我的 X86_64 主機使用的是 Ubunt…

書摘 ASP.NET Core技術內幕與項目實戰:基于DDD與前后端分離

IT行業的發展瞬息萬變,新技術層出不窮,很多技術人員出于個人興趣、個人職業發展等考慮而選擇一些流行的新技術,他們會把各種復雜的架構模式、高精尖的技術都加入架構中,這增加了項目的復雜度、延長了交付周期、增加了項目的研發成本。有些技術并不符合公司的情況,最后項目…

神策數據接入 DeepSeek,AI 賦能數據分析與智能運營

在 AI 技術迅猛發展的浪潮下&#xff0c;神策數據正在加速推進人工智能在數據分析和智能運營領域的深度應用。近日&#xff0c;神策數據宣布全面接入 DeepSeek&#xff0c;為企業客戶帶來更加智能化、高效的數據分析與智能運營服務。這一舉措展現了神策數據在人工智能方向的探索…

c++ 類和對象 —— 中 【復習筆記】

1. 類的默認成員函數 如果一個類什么成員都沒有&#xff0c;簡稱空類。但實際上&#xff0c;任何類在不寫成員時&#xff0c;編譯器會自動生成6個默認成員函數&#xff08;用戶未顯式實現&#xff0c;編譯器生成的成員函數&#xff09; 這6個成員函數可分為三類&#xff1a; …