數據驅動編程的核心出發點是相對於程序邏輯,編程更擅長於處理數據。數據比程序邏輯更容易駕馭,所以我們應該盡可能的將編程設計的復雜度從程序代碼轉移至數據。
真的是這樣嗎?讓我們來看一個示例。
假設有一個程序,需要處理其他程序發送的消息,消息類型是字符串,每個消息都需要一個函數進行處理。第一印象,我們可能會這樣處理:
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);
}
}
消息類型可能還會增加。看着常常的流程可能有點累,檢測一下中間某個消息有沒有處理也比較費勁,而且,每增加一個消息,就要增加一個流程分支。
按照數據驅動編程的思路,可能會這樣設計:
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}
};
void msg_proc(const char *msg_type, const char *msg_buf)
{
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編程藝術》作者。
---------------------
來源:此文章來自CSDN
原文:https://blog.csdn.net/chgaowei/article/details/6658260
本人是一名phper,對文中的代碼不是很熟,可以看懂,但並不影響我們對數據驅動這個詞匯的理解。