天天看點

[轉]什麼是資料驅動程式設計

前言:

最近在學習《Unix程式設計藝術》。以前粗略的翻過,以為是介紹unix工具的。現在認真的看了下,原來是介紹設計原則的。它的核心就是第一章介紹的unix的哲學以及17個設計原則,而後面的内容就是圍繞它來展開的。以前說過,要學習适合自己的資料,而判斷是否适合的一個方法就是看你是否能夠讀得下去。我對這本書有一種相見恨晚的感覺。推薦有4~6年工作經驗的朋友可以讀一下。

正題:

作者在介紹Unix設計原則時,其中有一條為“表示原則:把知識疊入資料以求邏輯質樸而健壯”。結合之前自己的一些經驗,我對這個原則很有共鳴,是以先學習了資料驅動程式設計相關的内容,這裡和大家分享出來和大家一起讨論。

資料驅動程式設計的核心

資料驅動程式設計的核心出發點是相對于程式邏輯,人類更擅長于處理資料。資料比程式邏輯更容易駕馭,是以我們應該盡可能的将設計的複雜度從程式代碼轉移至資料。

真的是這樣嗎?讓我們來看一個示例。

假設有一個程式,需要處理其他程式發送的消息,消息類型是字元串,每個消息都需要一個函數進行處理。第一印象,我們可能會這樣處理: 

void msg_proc(const char *msg_type, const char *msg_buf) 

    if (0 == strcmp(msg_type, "inivite")) 

    { 

        inivite_fun(msg_buf); 

    } 

    else if (0 == strcmp(msg_type, "tring_100")) 

        tring_fun(msg_buf); 

    else if (0 == strcmp(msg_type, "ring_180")) 

        ring_180_fun(msg_buf); 

    else if (0 == strcmp(msg_type, "ring_181")) 

        ring_181_fun(msg_buf); 

    else if (0 == strcmp(msg_type, "ring_182")) 

        ring_182_fun(msg_buf); 

    else if (0 == strcmp(msg_type, "ring_183")) 

        ring_183_fun(msg_buf); 

    else if (0 == strcmp(msg_type, "ok_200")) 

        ok_200_fun(msg_buf); 

    }

    。。。。。。      else if (0 == strcmp(msg_type, "fail_486"))          fail_486_fun(msg_buf);      else          log("未識别的消息類型%s\n", msg_type);  }  上面的消息類型取自sip協定(不完全相同,sip協定借鑒了http協定),消息類型可能還會增加。看着常常的流程可能有點累,檢測一下中間某個消息有沒有處理也比較費勁,而且,沒增加一個消息,就要增加一個流程分支。 按照資料驅動程式設計的思路,可能會這樣設計:  typedef void (*SIP_MSG_FUN)(const char *); typedef struct __msg_fun_st      const char *msg_type;//消息類型      SIP_MSG_FUN fun_ptr;//函數指針  }msg_fun_st; msg_fun_st msg_flow[] =          {"inivite", inivite_fun},          {"tring_100", tring_fun},          {"ring_180", ring_180_fun},          {"ring_181", ring_181_fun},          {"ring_182", ring_182_fun},          {"ring_183", ring_183_fun},          {"ok_200", ok_200_fun},         。。。。。。          {"fail_486", fail_486_fun}  };     int type_num = sizeof(msg_flow) / sizeof(msg_fun_st);      int i = 0;     for (i = 0; i < type_num; i++)          if (0 == strcmp(msg_flow[i].msg_type, msg_type))          {              msg_flow[i].fun_ptr(msg_buf);              return ;          }      log("未識别的消息類型%s\n", msg_type); 

下面這種思路的優勢:

1、可讀性更強,消息處理流程一目了然。

2、更容易修改,要增加新的消息,隻要修改資料即可,不需要修改流程。

3、重用,第一種方案的很多的else if其實隻是消息類型和處理函數不同,但是邏輯是一樣的。下面的這種方案就是将這種相同的邏輯提取出來,而把容易發生變化的部分提到外面。

隐含在背後的思想:

很多設計思路背後的原理其實都是相通的,隐含在資料驅動程式設計背後的實作思想包括:

1、控制複雜度。通過把程式邏輯的複雜度轉移到人類更容易處理的資料中來,進而達到控制複雜度的目标。

2、隔離變化。像上面的例子,每個消息處理的邏輯是不變的,但是消息可能是變化的,那就把容易變化的消息和不容易變化的邏輯分離。

3、機制和政策的分離。和第二點很像,本書中很多地方提到了機制和政策。上例中,我的了解,機制就是消息的處理邏輯,政策就是不同的消息處理(後面想專門寫一篇文章介紹下機制和政策)。

資料驅動程式設計可以用來做什麼:

如上例所示,它可以應用在函數級的設計中。

同時,它也可以應用在程式級的設計中,典型的比如用表驅動法實作一個狀态機(後面寫篇文章專門介紹)。

也可以用在系統級的設計中,比如DSL(這方面我經驗有些欠缺,目前不是非常确定)。

它不是什麼:

1、 它不是一個全新的程式設計模型:它隻是一種設計思路,而且曆史悠久,在unix/linux社群應用很多;

2、它不同于面向對象設計中的資料:“資料驅動程式設計中,資料不但表示了某個對象的狀态,實際上還定義了程式的流程;OO看重的是封裝,而資料驅動程式設計看重的是編寫盡可能少的代碼。”

書中的值得思考的話:

資料壓倒一切。如果選擇了正确的資料結構并把一切組織的井井有條,正确的算法就不言自明。程式設計的核心是資料結構,而不是算法。——Rob Pike

程式員束手無策。。。。。隻有跳脫代碼,直起腰,仔細思考資料才是最好的行動。表達式程式設計的精髓。——Fred Brooks

資料比程式邏輯更易駕馭。盡可能把設計的複雜度從代碼轉移至資料是個好實踐。——《unix程式設計藝術》作者。

本文轉自feisky部落格園部落格,原文連結:http://www.cnblogs.com/feisky/archive/2012/02/04/2338520.html,如需轉載請自行聯系原作者

繼續閱讀