首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> C語言 >> 關於C語言

C++ 沉思錄課堂練習另解:以訊息傳遞替代設計模式(優化版)

     編輯:關於C語言

動機:拒絕過度設計

原書以裝飾、組合等多重模式解決「圖片加框、橫向/縱向拼接」問題,引入大量介面、虛函數、繼承層次。作者認為:每多一個模式就多一層間接層,偏離問題本質。本文採用「訊息傳遞」極簡風格,無繼承、無虛函數,核心僅 100 行左右。

核心抽象:圖片訊息結構

enum { PM_WIDTH, PM_HEIGHT, PM_ROW };

struct PictureMsg {
    using Proc = int(*)(void* pThis, int msg, void* p1, void* p2);
    void* pThis;
    Proc  proc;

    int GetWidth()  { return proc(pThis, PM_WIDTH,  nullptr, nullptr); }
    int GetHeight() { return proc(pThis, PM_HEIGHT, nullptr, nullptr); }
    int GetRow(int r, std::string& s) { return proc(pThis, PM_ROW, (void*)r, &s); }
};

// 輸出運算子:逐行取得字串並換行
std::ostream& operator<<(std::ostream& out, PictureMsg& msg) {
    for (int r=0, h=msg.GetHeight(); r

基礎圖片實作

class CPicture : public PictureMsg {
    const char** data_; int count_, width_;
    static int HandleMsg(void* pThis, int msg, void* p1, void* p2) {
        auto self = (CPicture*)pThis;
        switch (msg) {
            case PM_WIDTH:  return self->width_;
            case PM_HEIGHT: return self->count_;
            case PM_ROW: {
                int r = (int)p1; auto& s = *(std::string*)p2;
                if (r >= self->count_) break;
                for (int i=0; self->data_[r][i]; ++i) s.push_back(self->data_[r][i]);
                for (int i=s.size(); iwidth_; ++i) s.push_back(' ');
            }
        } return 0;
    }
public:
    CPicture(const char* d[], int n) : data_(d), count_(n), width_(0) {
        for (int i=0;i

裝飾器:以訊息攔截實現加框、橫向拼接

// 加框:攔截 WIDTH/HEIGHT/ROW,在外層添加 + - | 字元
class CFrameDecorater {
    PictureMsg prev_;
    static int HandleMsg(void* pThis, int msg, void* p1, void* p2) {
        auto self = (CFrameDecorater*)pThis; 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& s = *(std::string*)p2;
                if (r == 0 || r > p.GetHeight()) {          // 頂/底框
                    s.push_back('+');
                    for (int i=0;ileft_.GetWidth() + self->right_.GetWidth();
            case PM_HEIGHT: return std::max(self->left_.GetHeight(), self->right_.GetHeight());
            case PM_ROW: {
                int r = (int)p1; auto& s = *(std::string*)p2;
                PrintRow(self->left_,  r, s);
                PrintRow(self->right_, r, s);
            }
        } return 0;
    }
public:
    CHorseDecorater(PictureMsg& L, PictureMsg& R) : left_(L), right_(R) {
        L.pThis = this; L.proc = HandleMsg;
        R.pThis = this; R.proc = HandleMsg;
    }
};

客戶端程式碼:鏈式裝飾,原圖物件不變

int main() {
    const char* pic[] = {"Paris","in the","Spring","HaHa"};
    CPicture p1(pic, 3), p2(pic, 4);

    CFrameDecorater f1(p1);           // p1 加框
    CFrameDecorater f2(p1);           // p1 再加框(雙層)
    CHorseDecorater h1(p1, p2);       // p1 | p2
    CFrameDecorater f3(p1);           // 整體再加框
    CHorseDecorater h2(p2, p1);       // p2 | p1
    CFrameDecorater f4(p2);
    CHorseDecorater h3(p1, p2);

    std::cout << p1;                  // 只印 p1,卻反映所有裝飾結果
}

優勢總結

  • 零繼承、零虛函數、零動態分配(裝飾器為棧上物件);
  • 原圖 CPicture 完全不知情,符合「開放封閉原則」;
  • 訊息結構可輕易擴展(如新增 PM_CLONE 支援深拷貝);
  • 編譯期即可內聯最佳化,效能極高。
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved