前文(ID 1647)已闡述消息驅動核心思想。本文作為補充,提供**更完整的 C++ 版本**(含 `std::string`、垂直拼接 `CVerticalDecorater`、記憶體安全管理),並深入剖析「介面劫持」機制與為何它能替代所有裝飾/組合模式類別體系。
enum { PM_WIDTH, PM_HEIGHT, PM_ROW };
struct PictureMsg {
using Proc = int(*)(void*, int, void*, void*);
void* obj = nullptr;
Proc proc = nullptr;
int GetWidth() const { return proc(obj, PM_WIDTH, 0, 0); }
int GetHeight() const { return proc(obj, PM_HEIGHT, 0, 0); }
int GetRow(int row, std::string& out) const {
return proc(obj, PM_ROW, (void*)row, (void*)&out);
}
};
std::ostream& operator<<(std::ostream& os, const PictureMsg& msg) {
for (int r = 0; r < msg.GetHeight(); ++r) {
std::string line; msg.GetRow(r, line);
os << line << '\n';
}
return os;
}
class CPicture : public PictureMsg {
const char** data_; int rows_, width_;
static int Handle(void* obj, int msg, void* p1, void* p2) {
auto self = (CPicture*)obj;
switch (msg) {
case PM_WIDTH: return self->width_;
case PM_HEIGHT: return self->rows_;
case PM_ROW: {
int r = (int)p1; auto& out = *(std::string*)p2;
if (r >= self->rows_) return 0;
out = self->data_[r];
out.append(self->width_ - out.size(), ' ');
return 0;
}
}
return 0;
}
public:
CPicture(const char* d[], int n) : data_(d), rows_(n), width_(0) {
for (int i=0;i
template
struct DecoraterBase : PictureMsg {
PictureMsg prev_;
DecoraterBase(PictureMsg& prev) : prev_(prev) {
prev_.obj = static_cast(this);
prev_.proc = &Derived::Handle;
}
};
struct CFrameDecorater : DecoraterBase {
using Base = DecoraterBase;
CFrameDecorater(PictureMsg& p) : Base(p) {}
static int Handle(void* obj, int msg, void* p1, void* p2) {
auto self = (CFrameDecorater*)obj;
auto& p = self->prev_;
switch (msg) {
case PM_WIDTH: return p.GetWidth() + 2;
case PM_HEIGHT: return p.GetHeight() + 2;
case PM_ROW: {
int r = (int)p1; auto& out = *(std::string*)p2;
if (r == 0 || r == p.GetHeight()+1) {
out = "+" + std::string(p.GetWidth(), '-') + "+";
} else {
std::string mid; p.GetRow(r-1, mid);
out = "|" + mid + "|";
}
return 0;
}
}
return 0;
}
};
struct CHorseDecorater : DecoraterBase {
PictureMsg right_;
using Base = DecoraterBase;
CHorseDecorater(PictureMsg& l, PictureMsg& r) : Base(l), right_(r) {}
static int Handle(void* obj, int msg, void* p1, void* p2) {
auto self = (CHorseDecorater*)obj;
auto& L = self->prev_;
auto& R = self->right_;
switch (msg) {
case PM_WIDTH: return L.GetWidth() + R.GetWidth();
case PM_HEIGHT: return std::max(L.GetHeight(), R.GetHeight());
case PM_ROW: {
int r = (int)p1; auto& out = *(std::string*)p2;
std::string l, rstr;
if (r < L.GetHeight()) L.GetRow(r, l); else l = std::string(L.GetWidth(), ' ');
if (r < R.GetHeight()) R.GetRow(r, rstr); else rstr = std::string(R.GetWidth(), ' ');
out = l + rstr;
return 0;
}
}
return 0;
}
};
struct CVerticalDecorater : DecoraterBase {
PictureMsg bottom_;
using Base = DecoraterBase;
CVerticalDecorater(PictureMsg& top, PictureMsg& bot) : Base(top), bottom_(bot) {}
static int Handle(void* obj, int msg, void* p1, void* p2) {
auto self = (CVerticalDecorater*)obj;
auto& T = self->prev_;
auto& B = self->bottom_;
switch (msg) {
case PM_WIDTH: return std::max(T.GetWidth(), B.GetWidth());
case PM_HEIGHT: return T.GetHeight() + B.GetHeight();
case PM_ROW: {
int r = (int)p1; auto& out = *(std::string*)p2;
if (r < T.GetHeight()) T.GetRow(r, out);
else B.GetRow(r - T.GetHeight(), out);
// 補齊寬度
int w = std::max(T.GetWidth(), B.GetWidth());
if ((int)out.size() < w) out.append(w - out.size(), ' ');
return 0;
}
}
return 0;
}
};
int main() {
const char* d[] = {"Paris", "in the", "Spring", "HaHa"};
CPicture p1(d, 3), p2(d, 4);
// 疊加多層邊框
CFrameDecorater f1(p1), f2(p1); // p1 介面現指向 f2 → f1 → p1
// 水平拼接 + 邊框
CHorseDecorater h(p1, p2);
CFrameDecorater fh(p1); // p1 現為 fh → h → (f2→f1→p1) + p2
// 垂直拼接
CVerticalDecorater v(p1, p2);
std::cout << "=== Final p1 ===\n" << p1;
std::cout << "=== p2 (unmodified) ===\n" << p2;
return 0;
}
初始:p1.obj → CPicture::Handle CFrameDecorater f1(p1): p1.obj → f1, p1.proc → CFrameDecorater::Handle f1.prev_.obj → CPicture::Handle (原 p1 行為) CFrameDecorater f2(p1): p1.obj → f2, p1.proc → CFrameDecorater::Handle f2.prev_.obj → f1 (f1 仍指向 CPicture) CHorseDecorater h(p1, p2): p1.obj → h, p1.proc → CHorseDecorater::Handle h.prev_.obj → f2 (f2→f1→CPicture) h.right_.obj → p2 (CPicture::Handle) CFrameDecorater fh(p1): p1.obj → fh, p1.proc → CFrameDecorater::Handle fh.prev_.obj → h (h→f2→f1→CPicture + p2)
這個解法證明:**設計模式的靈魂是「關注點分離與動態組合」,而非「繼承與虛函數」**。消息驅動(或稱攔截器鏈、中介者模式的極簡形式)以最小機制實現了最大靈活性。下次面對「需支援任意組合的裝飾/管道/過濾器」問題時,請先考慮:
struct Interface { void* obj; int(*proc)(void*, int, void*, void*); };
這或許就是你需要的全部框架。