多范式融合 C++ 软件设计解析
核心思想:
不依赖单一范式,而是根据场景选择最合适的范式和 C++ 特性来解决问题。
1⃣ 多范式设计原则
- 分场景灵活选择范式
- 指令式、过程式、面向对象、函数式、响应式等范式各有优势
- 根据问题域选择合适的范式,而不是“一统江湖”
- 领域驱动设计(DDD)视角
- 将软件划分为不同的 域(Domain)/ 层(Layer)
- 每个域可以采用不同范式:
- 核心业务逻辑 → 面向对象或函数式
- 流程控制 → 过程式或指令式
- 数据流 / 异步事件 → 响应式
- C++ 特性支撑
- 类/对象、模板、Lambda、智能指针、并发库等
- 不滥用语法特性,避免复杂度和不可维护性
- DCI 架构实现多范式融合
- D (Data):领域对象 → 面向对象
- C (Context):业务场景 → 过程式 / 函数式组合
- I (Interaction):角色/职责 → 高阶函数 / Lambda / 闭包
2⃣ C++ 示例:多范式融合 + DCI
我们用一个 电商购买流程 作为例子:
#include <iostream>
#include <string>
#include <memory>
#include <functional>
#include <vector>
//////////////////////
// D: Data - 领域对象
//////////////////////
class User {
public:
std::string name;
int balance;
User(std::string n, int b) : name(n), balance(b) {}
};
class Product {
public:
std::string name;
int price;
Product(std::string n, int p) : name(n), price(p) {}
};
//////////////////////
// C: Context - 业务场景
//////////////////////
class PurchaseContext {
public:
User& user;
Product& product;
PurchaseContext(User& u, Product& p) : user(u), product(p) {}
// I: Interaction - 使用 Lambda 封装角色行为
std::function<void()> checkout() {
return [this]() {
if(user.balance >= product.price) {
user.balance -= product.price;
std::cout << user.name << " purchased "
<< product.name
<< ", remaining balance: " << user.balance
<< std::endl;
} else {
std::cout << user.name << " has insufficient balance." << std::endl;
}
};
}
};
//////////////////////
// 程序入口
//////////////////////
int main() {
// 数据域
User alice("Alice", 100);
Product book("C++ Book", 30);
// 场景域
PurchaseContext ctx(alice, book);
// 执行交互
auto action = ctx.checkout();
action(); // 执行 Lambda 闭包
return 0;
}
理解:
- D(Data)
User、Product→ 面向对象封装数据- 提供属性、但不包含业务逻辑
- C(Context)
PurchaseContext→ 封装业务场景- 负责协调数据对象和角色交互
- I(Interaction)
checkout()返回 Lambda 闭包- 封装操作逻辑 → 高阶函数 + 函数式设计
- 执行时绑定上下文,实现职责与数据分离
- 分范式使用
- 面向对象 → 数据封装
- 函数式 → 闭包、Lambda 封装角色行为
- 过程式 → main() 里调用上下文执行操作
3⃣ 公式化描述
业务流程可抽象为:
Result=I(C(D))
\text{Result} = I(C(D))
Result=I(C(D))
- DDD → 数据对象域 (User, Product)
- CCC → 业务上下文/场景 (PurchaseContext)
- III → 角色交互/操作 (checkout Lambda)
- 执行流程:
User,Product→PurchaseContextcheckout()→invokeResult User, Product \xrightarrow{PurchaseContext} \text{checkout()} \xrightarrow{invoke} Result User,ProductPurchaseContextcheckout()invokeResult
4⃣ 优点总结
- 分域使用范式 → 灵活选择最佳策略
- 职责与数据分离 → 易于维护和测试
- 闭包实现高阶函数 → 可组合、可扩展
- 避免单一范式拥坌 → 面向对象、函数式、过程式协同
5⃣ 可扩展示例
- 可以增加 事件流 / 响应式处理:
std::vector<std::function<void()>> eventQueue;
eventQueue.push_back(ctx.checkout());
// 异步执行
for(auto& e : eventQueue) e();
- 对应 RxCpp 风格:
Eevent=subscribe(checkout closure) E_{\text{event}} = \text{subscribe}(\text{checkout closure}) Eevent=subscribe(checkout closure)
✓ 总结: - 多范式融合 C++ 软件设计的关键是 “按域/层选择范式”
- DCI 架构提供自然的 Data → Context → Interaction 框架
- Lambda/闭包 + 面向对象 + 过程式结合 → 可组合、可扩展
- 响应式事件流可以进一步支持并发和异步处理
DCI(Data–Context–Interaction)设计过程
1⃣ Context1 — 生命周期管理 (Lifecycle)
理解
- Context1 代表生命周期管理的上下文。
- 状态机从 创建 (CREATED) → 初始化 (INITIALIZED) → 开始工作 (STARTWORKED) → 结束。
ILifecycle定义了生命周期接口:onCreated()— 创建时触发onFinished()— 完成时触发onTimeout()— 超时触发OnlineOf(Whom&)/OfflineOf(Whom&)— 管理伙伴上线/离线状态
LifecycleImplA/B是具体实现类,可以复用在不同业务对象上。
公式理解:如果定义 Context 生命周期长度为 TlifeT_\text{life}Tlife,且初始化耗时 tinitt_\text{init}tinit,则有效工作时间 TworkT_\text{work}Twork 可以近似表示为:
Twork=Tlife−tinit−ttimeout T_\text{work} = T_\text{life} - t_\text{init} - t_\text{timeout} Twork=Tlife−tinit−ttimeout
2⃣ Context2 — Handler 与 Stream
理解
- Context2 负责消息处理和数据流调度。
IHandler定义了proc(Msg&)消息处理接口。ISchedulable提供调度能力。MsgHandler和FixScheduler是接口实现类。- Stream Choreography 体现响应式编程思想:
- 数据从 触发者 (Scheduler) 流向 Stream
- Stream 根据 Processor 处理
- 使用
.on().take().map().subscribe()类似 Rx 风格操作
公式表示:若每条消息处理耗时 tproct_\text{proc}tproc,处理速率为 Rproc=1/tprocR_\text{proc} = 1/t_\text{proc}Rproc=1/tproc,则系统处理能力约为:
Csystem=∑iRproc,i C_\text{system} = \sum_i R_{\text{proc},i} Csystem=i∑Rproc,i
3⃣ Role & Implementations — 角色和业务对象
理解
- BusinessObject (BizObj) 是 DCI 中的 Data,即数据对象。
- 各个 Role 实现类(LifecycleImpl, MsgHandler, Scheduler)通过绑定
BizObj实现交互逻辑。 - 基础设施(Infrastructure)提供:
Factory— 创建 BizObjRepository— 保存/查询 BizObj
公式解释:若业务对象状态向量为 s=[s1,s2,...,sn]\mathbf{s} = [s_1, s_2, ..., s_n]s=[s1,s2,...,sn],角色作用函数为 frole(s)f_\text{role}(\mathbf{s})frole(s),则交互后的新状态为:
s′=frole(s) \mathbf{s}' = f_\text{role}(\mathbf{s}) s′=frole(s)
4⃣ Combination — 上下文组合与交互
理解
- 上下文组合体现 DCI 中 Context 驱动 Role 交互:
- Context1 管理生命周期
- Context2 管理消息和流
- 它们通过 BizObj 共享状态和功能
- 交互逻辑:
LifecycleImplA使用MsgHandlerLifecycleImplB使用FixScheduler
公式表示:假设上下文间交互函数为 g(C1,C2)g(C_1, C_2)g(C1,C2),则系统整体行为可抽象为:
SystemBehavior=g(Context1,Context2) \text{SystemBehavior} = g(\text{Context1}, \text{Context2}) SystemBehavior=g(Context1,Context2)
5⃣ 总结理解
- Data(数据):BizObj — 核心业务对象
- Context(上下文):Context1 / Context2 — 组织角色交互的环境
- Interaction / Role(角色交互):LifecycleImpl, MsgHandler, Scheduler — 动态绑定到 BizObj,实现特定功能
- Infrastructure(基础设施):Factory, Repository — 创建和持久化数据
- DCI 核心思想:
- 数据对象和角色职责分离
- 上下文定义角色组合与交互流程
- 使用上下文驱动对象行为,不污染数据对象本身
/**
* ============================================================
* DCI (Data-Context-Interaction) 完整示例 —— 超详细注释版
* ============================================================
*
* 架构分层:
*
* D —— Data
* BusinessObject
* 只保存状态,不包含业务逻辑
*
* I —— Interaction (Role)
* LifecycleImplA / MsgHandler / FixScheduler
* 角色 = 给数据“赋予行为”
*
* C —— Context
* Context1_Lifecycle
* Context2_HandlerStream
* 负责组织角色之间的协作
*
* Infra —— 基础设施
* Factory / Repository
*
* 关键思想:
*
* 行为 ∉ 数据
* 行为 ∈ 角色
* 流程 ∈ 上下文
*
*/
#include <iostream>
#include <functional>
#include <string>
#include <vector>
#include <unordered_map>
#include <memory>
#include <stdexcept>
#include <algorithm>
#include <climits>
///////////////////////////////////////////////////////////////
// SECTION 1 — DATA 层(D)
// 纯数据对象,不包含任何业务逻辑
///////////////////////////////////////////////////////////////
struct Msg {
int id; // 消息编号
std::string payload; // 消息内容
};
// 前向声明
class BusinessObject;
using BizObjPtr = std::shared_ptr<BusinessObject>;
/**
* BusinessObject —— DCI 中的 Data
*
* 设计原则:
* - 不包含行为
* - 不知道生命周期
* - 不知道消息处理
* - 只保存状态
*/
class BusinessObject {
public:
BusinessObject(int id, std::string name)
: id_(id), name_(std::move(name)) {}
int id() const { return id_; }
std::string name() const { return name_; }
// ===== 纯状态字段 =====
std::string status = "idle"; // 当前业务状态
int msgCount = 0; // 已处理消息数量
private:
int id_; // 唯一标识
std::string name_; // 名称
};
///////////////////////////////////////////////////////////////
// SECTION 2 — INFRA 层
///////////////////////////////////////////////////////////////
/**
* Repository —— 模拟持久化层
*
* 作用:
* - 保存业务对象
* - 查询业务对象
*
* 注意:
* 这属于基础设施层,不属于 DCI 核心
*/
class Repository {
public:
void save(BizObjPtr obj) {
store_[obj->id()] = obj;
std::cout << "[Repository] save id=" << obj->id() << "\n";
}
BizObjPtr find(int id) {
auto it = store_.find(id);
if (it == store_.end())
throw std::runtime_error("not found");
return it->second;
}
private:
std::unordered_map<int, BizObjPtr> store_;
};
/**
* Factory —— 创建 Data 对象
*
* 设计意义:
* 把对象创建与业务逻辑分离
*/
class Factory {
public:
Factory(Repository& repo)
: repo_(repo), nextId_(1) {}
BizObjPtr create(const std::string& name) {
auto obj = std::make_shared<BusinessObject>(nextId_++, name);
repo_.save(obj);
return obj;
}
private:
Repository& repo_;
int nextId_;
};
///////////////////////////////////////////////////////////////
// SECTION 3 — Interaction 层(Role)
///////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////
// 生命周期角色接口
///////////////////////////////////////////////////////////////
enum class LifecycleState {
CREATED,
INITIALIZED,
STARTWORKED,
FINISHED
};
/**
* ILifecycle —— 角色接口
*
* 定义:
* 这个角色“能做什么”
*/
class ILifecycle {
public:
virtual ~ILifecycle() = default;
virtual void onCreated() = 0;
virtual void onFinished() = 0;
virtual void onTimeout() = 0;
virtual void onlineOf(const std::string&) = 0;
virtual void offlineOf(const std::string&) = 0;
};
/**
* LifecycleImplA —— 状态机实现
*
* 这是一个“角色”
* 它持有 Data 引用
* 它改变 Data 的状态
*
* 关键:
* 数据对象不知道状态机
* 状态机属于角色
*/
class LifecycleImplA : public ILifecycle {
public:
explicit LifecycleImplA(BizObjPtr obj)
: obj_(obj), state_(LifecycleState::CREATED) {}
void onCreated() override {
state_ = LifecycleState::CREATED;
obj_->status = "created"; // 修改 Data
log("CREATED");
}
void initialize() {
state_ = LifecycleState::INITIALIZED;
obj_->status = "initialized";
log("INITIALIZED");
}
void onlineOf(const std::string& whom) override {
partners_.push_back(whom);
// 如果两个伙伴上线 → 开始工作
if (partners_.size() >= 2) {
state_ = LifecycleState::STARTWORKED;
obj_->status = "working";
log("STARTWORKED");
}
}
void offlineOf(const std::string& whom) override {
partners_.erase(
std::remove(partners_.begin(), partners_.end(), whom),
partners_.end()
);
}
void onFinished() override {
state_ = LifecycleState::FINISHED;
obj_->status = "finished";
log("FINISHED");
}
void onTimeout() override {
state_ = LifecycleState::FINISHED;
obj_->status = "timeout";
log("TIMEOUT");
}
private:
BizObjPtr obj_; // 被注入的数据
LifecycleState state_;
std::vector<std::string> partners_;
void log(const std::string& s) {
std::cout << "[Lifecycle] " << s << "\n";
}
};
///////////////////////////////////////////////////////////////
// 消息处理角色
///////////////////////////////////////////////////////////////
enum class Status { OK, ERROR };
class IHandler {
public:
virtual ~IHandler() = default;
virtual Status proc(const Msg&) = 0;
};
/**
* MsgHandler —— 消息处理角色
*
* 作用:
* 读取数据
* 修改数据
*/
class MsgHandler : public IHandler {
public:
explicit MsgHandler(BizObjPtr obj)
: obj_(obj) {}
Status proc(const Msg& msg) override {
// 修改 Data 的状态
obj_->msgCount++;
std::cout
<< "[Handler] msg#"
<< msg.id
<< " payload="
<< msg.payload
<< " total="
<< obj_->msgCount
<< "\n";
return Status::OK;
}
private:
BizObjPtr obj_;
};
///////////////////////////////////////////////////////////////
// Scheduler 角色
///////////////////////////////////////////////////////////////
class ISchedulable {
public:
virtual ~ISchedulable() = default;
virtual void schedule(std::function<void()>, int) = 0;
virtual void stop() = 0;
};
class FixScheduler : public ISchedulable {
public:
explicit FixScheduler(BizObjPtr obj)
: obj_(obj) {}
void schedule(std::function<void()> task, int interval) override {
std::cout
<< "[Scheduler] interval="
<< interval
<< "\n";
// 简化为立即执行一次
task();
}
void stop() override {
std::cout << "[Scheduler] stopped\n";
}
private:
BizObjPtr obj_;
};
///////////////////////////////////////////////////////////////
// SECTION 4 — Context 层(C)
///////////////////////////////////////////////////////////////
/**
* Context1 —— 生命周期上下文
*
* 职责:
* 组织 Lifecycle 角色的调用顺序
*
* 关键:
* 上下文定义“流程”
*/
class Context1_Lifecycle {
public:
Context1_Lifecycle(BizObjPtr obj,
std::shared_ptr<LifecycleImplA> lc)
: obj_(obj), lc_(lc) {}
void run() {
lc_->onCreated();
lc_->initialize();
lc_->onlineOf("A");
lc_->onlineOf("B");
lc_->onFinished();
}
private:
BizObjPtr obj_;
std::shared_ptr<LifecycleImplA> lc_;
};
/**
* Context2 —— 消息处理上下文
*
* 职责:
* 组织 Handler + Scheduler
*/
class Context2_HandlerStream {
public:
Context2_HandlerStream(
BizObjPtr obj,
std::shared_ptr<MsgHandler> handler,
std::shared_ptr<FixScheduler> scheduler)
: obj_(obj),
handler_(handler),
scheduler_(scheduler) {}
void run() {
std::vector<Msg> inbox = {
{1,"hello"},
{2,"world"}
};
for (auto& m : inbox) {
handler_->proc(m);
}
scheduler_->schedule([&](){
std::cout << "msgCount="
<< obj_->msgCount
<< "\n";
}, 500);
scheduler_->stop();
}
private:
BizObjPtr obj_;
std::shared_ptr<MsgHandler> handler_;
std::shared_ptr<FixScheduler> scheduler_;
};
///////////////////////////////////////////////////////////////
// MAIN —— 组装所有组件
///////////////////////////////////////////////////////////////
int main() {
Repository repo;
Factory factory(repo);
// 创建 Data
auto biz = factory.create("OrderProcessor");
// 创建角色(注入 Data)
auto lc = std::make_shared<LifecycleImplA>(biz);
auto handler = std::make_shared<MsgHandler>(biz);
auto scheduler = std::make_shared<FixScheduler>(biz);
// 创建 Context
Context1_Lifecycle c1(biz, lc);
Context2_HandlerStream c2(biz, handler, scheduler);
// 执行上下文
c1.run();
c2.run();
repo.save(biz);
std::cout
<< "Final status="
<< biz->status
<< " msgCount="
<< biz->msgCount
<< "\n";
}
这份代码已经是一个结构非常清晰的 DCI 示例。
一、DCI 的核心思想到底是什么?
DCI 不是“把类拆开”这么简单。
它的本质是:
对象只表示“是什么”(Data)
行为来自“它在当前场景中扮演什么角色”(Role)
场景由 Context 组织
可以用一个抽象公式表示:
Behavior=Context(Role(Data)) Behavior = Context(Role(Data)) Behavior=Context(Role(Data))
或者更直观一点:
SystemBehavior=C(D,R) SystemBehavior = C(D, R) SystemBehavior=C(D,R)
- DDD = Data(数据对象)
- RRR = Role(角色行为)
- CCC = Context(流程组织者)
二、你这份代码中的 DCI 映射
我们逐层拆解。
① Data —— BusinessObject
class BusinessObject {
std::string status;
int msgCount;
};
它只做三件事:
- 保存 id
- 保存 name
- 保存状态数据
它: - 不知道生命周期状态机
- 不知道如何处理消息
- 不知道调度器
- 不知道上下文
它只是“状态容器”。
这就是 DCI 的第一原则:
数据模型不承载业务流程。
② Role —— Interaction(行为的载体)
例如:
class LifecycleImplA
class MsgHandler
class FixScheduler
这些类有一个共同点:
BizObjPtr obj_;
它们:
- 不拥有数据
- 只“借用”数据
- 修改数据
- 读取数据
举个关键点:
obj_->msgCount++;
Data 本身没有“处理消息”的能力。
处理能力来自 MsgHandler 这个角色。
这说明:
行为是外部赋予的,而不是内建的。
③ Context —— 行为的编排者
例如:
class Context1_Lifecycle
class Context2_HandlerStream
它们:
- 决定调用顺序
- 决定角色如何协作
- 决定执行流程
比如:
lc_->onCreated();
lc_->initialize();
lc_->onlineOf("A");
lc_->onlineOf("B");
lc_->onFinished();
Data 不知道这些流程。
Role 也不知道整个业务流程。
流程只存在于 Context。
这就是 DCI 最核心的分离:
| 层 | 负责什么 |
|---|---|
| Data | 状态 |
| Role | 行为 |
| Context | 流程 |
三、DCI 的本质:对象 ≠ 行为
在传统 OOP 中:
class Order {
void process();
void finish();
};
行为和数据绑死在一起。
在 DCI 中:
Order // 只是数据
OrderProcessorRole
OrderLifecycleRole
OrderBillingRole
一个对象可以在不同 Context 中扮演不同角色。
这意味着:
SameData+DifferentContext→DifferentBehavior
SameData + DifferentContext → DifferentBehavior
SameData+DifferentContext→DifferentBehavior
四、你这份代码真正体现的核心哲学
1⃣ 行为是“动态赋予”的
auto lc = std::make_shared<LifecycleImplA>(biz);
你在 main 中“注入角色”。
这意味着:
- 角色不是数据固有的
- 角色是场景决定的
这就是 DCI 的“动态建模能力”。
2⃣ Context 决定系统行为
看 main:
c1.run();
c2.run();
执行顺序决定系统最终状态。
可以抽象成:
FinalState=C2(C1(D))
FinalState = C_2(C_1(D))
FinalState=C2(C1(D))
先生命周期,再消息处理。
如果顺序改变,结果可能不同。
3⃣ 角色之间不直接耦合
LifecycleImplA 不知道 MsgHandler。
MsgHandler 不知道 Lifecycle。
它们唯一共享的是:
BusinessObject
这叫:
通过数据对象进行间接协作。
五、DCI 相比传统 OOP 的核心优势
① 降低类爆炸
传统:
OrderWithLifecycleAndHandlerAndScheduler
DCI:
Order (Data)
+ LifecycleRole
+ HandlerRole
+ SchedulerRole
角色可复用。
② 避免“胖对象”
Data 不再变成上千行代码。
③ 场景驱动设计
系统行为可以形式化为:
Behavior=f(Context,Data)
Behavior = f(Context, Data)
Behavior=f(Context,Data)
而不是:
Behavior=f(Data)
Behavior = f(Data)
Behavior=f(Data)
六、DCI 的哲学核心一句话
对象本身没有行为,
行为来自它在某个场景中的角色。
七、你这段代码是否“真正 DCI”?
是的,已经是比较正统的 DCI:
✓ Data 不含行为
✓ Role 持有 Data
✓ Context 组织流程
✓ 角色运行时注入
如果你再往前一步,可以:
- 把 Role 动态注册到 Data(更纯粹)
- 使用模板消除虚函数
- 使用角色容器支持多角色组合
八、总结一句话
你这段代码的 DCI 本质可以写成:
系统=上下文驱动的数据状态变换
系统 = 上下文驱动的数据状态变换
系统=上下文驱动的数据状态变换
或者更抽象:
Dt+1=Context(Role(Dt))
D_{t+1} = Context(Role(D_t))
Dt+1=Context(Role(Dt))
&spm=1001.2101.3001.5002&articleId=158348610&d=1&t=3&u=e9ed19e6346d468ba35777b6684187cb)
1万+

被折叠的 条评论
为什么被折叠?



