表驅動法應用的難點

2021-06-21 11:00:46 字數 4035 閱讀 1481

分類: coding

2013-07-31 23:21

550人閱讀

收藏舉報

coding

好的**總是將複雜的邏輯以分層的方式降低單個層次上的複雜度。複雜與簡單有乙個相互轉化的過程。

在涉及編碼解析的功能時,常常有乙個帶有長長一串case的switch,而且會不斷增長。為每乙個case搞個類就太誇張了,還是用表驅動(table driven)來取代它吧。這種應用已經太多了。而讓大家不去用的原因可能就乙個,認為表無法表達出屬性的差異。

比如一般而言有下面這樣乙個操作,大家肯定會覺得用表處理沒有問題。

operator function

add(x,y) addfunctionptr

sub(x,y) subfunctionptr

但是如果增加了乙個inc(x),它相對於先前兩個各有兩個引數就不一樣了。這就會被認為提取共性失敗,而放棄了表驅動法,又栽到switch..case的汪洋大海。

表驅動法就是兩個過程: i. 提取共性,做到為每個元素做一樣的事。把共性放到表中, 用查表法取代switch。 ii. 提供支援函式,因為提取共性後會要求有為這些共性服務的函式。第1步是比較簡單的,把第2步想透了才會提公升使用表驅動法的層次。

表驅動法,一方面簡化**實現,便於維護。(這裡的簡化強調地是上層實現邏輯的簡化。) 二是提高**的彈性,增減內容的成本低,甚至可以做到動態支援。

用乙個簡單的定義表驅動法的使用:

consttabletable = ,

};void handlingfunction(id)

} }

對應於上面兩個要點,就是table的定義和callhandlefunctionfortherow的寫法。 callhandlefunctionsforrow為每一行的處理提供了乙個一致的入口,這是表驅動法實現的關鍵,其原則為對每個元素都做同樣的事情,這裡同樣的事情應至少要理解為介面一致!下面討論兩個在實踐中常見的問題:相容不同資料型別和相容不同引數個數。

像前面的例子,只要讓function的定義相容兩個引數和乙個引數的情況就可以了。使用模板是乙個最佳解決方法,就是比較複雜一些。這個解決方案最後稍帶說一下。

先舉個例子說明一下公共函式的實現思路。 乙個維護一串屬性的類有三個方法,乙個寫值,乙個取值,還有乙個序列化函式(儲存和載入)。可以想像,如果加乙個屬性,就要增加至少三處**。(下面的示例沒有涉及序列化。)

下面是乙個向特別key寫入其值的操作,key代表的資料型別可能會不一樣, 如下示例(只用說明要點):

string getkeyvalue(string&key)

return value; }

使用表驅動法,最簡單的一種方法就是用函式過載來處理型別不同的情況。可以使用類似如下的方法實現:

//表的定義

static propertytablevalue propertytable = , ,

};//寫值,過載兩個函式來實現

bool

settings::setvalue(property_id id, const

char *value)

bool settings::setvalue(property_id id, int value)

//取值

int settings::getintvalue(property_id id)

const

char* settings::getstringvalue(property_id id)

這樣的**,只是勉強實現了表驅動的功能。觀察**可以看到仍然有兩個明顯的問題:

1. 表的定義太死板,缺少靈活性。在定義表時分配記憶體問題明顯。

2. setvalue和getvalue仍然有不少重複的**邏輯。

針對第乙個問題,可以使用智慧型指標和兩個表維護的介面來解決,實現動態增減屬性。針對第二個問題,是典型的c++多型問題,可以使用模板類來實現。即實現乙個代表值的類,將取值操作交給這個類完成。 如:

template

class settingvalue;

public:

t getvalue() ;

bool setvalue(t newvalue)

private:

t value;

};

對於字串的類,還需要特化處理,包括記憶體**和賦值操作。下面給出乙個賦值操作的特化實現:

template <>

bool settingvalue<

char *>::setvalue(

char * newvalue)

strcpy(

value,newvalue);

return

true; }

在這個基礎上,要實現動態表就更容易了。下面實現出另外乙份setting manager:

struct propertytablevaluev2 ;

static propertytablevaluev2 propertytable = , ,

}; class settingsv2

vpointer->setvalue(value);

return

true; }

template

t getvalue(property_idid)

};///[horky]省略部分**///

};

*注意在使用getvalue時要在函式後面加型別約束,如下:

printf

("settingsv2: id1 is %d\n"

, (mysetting.

getvalue

<

int>(

id1)));

printf

("settingsv2: id2 is %s\n"

,(mysetting.

getvalue

<

char

*>(

id2)));

到這裡,實現了乙個比較正常的表驅動方法了。但就問題而言,還至少有兩個化點:

a. 實現動態表。進一步降低屬性變化的成本,也更符合封裝的原則。

b. 將列舉id改為字串屬性,即以字串為id (以hash方式處理,不會明顯增加執行成本), 更加靈活。特別有利於序列化可讀的文字。

如果要再進一步,還可以增加乙個key的型別,來實現出可巢狀的引數設定。比如:

id2: (int)0

id2: (string)xhorky***

id3: (key)

id3_1:(int)1

id3_2:(float)0.3

針對開篇提到的問題,其實現方式也是使用模板類實現,貼出支援兩個引數的類定義就能理解了(如果只是針對這個例子,就有點殺機焉用宰牛刀的感覺!webkit的**裡這類似的應用。):

template

class operatorwithparameter2

private:

operatorwithparameter2(method method, param1 parameter1, param2 parameter2)

: m_method(method)

, m_parameter1(parameter1)

, m_parameter2(parameter2)

virtual

void perform()

private:

method m_method;

p1 m_parameter1;

p2 m_parameter2;

};

:

18章表驅動法

18章表驅動法的使用 1.含義 表驅動法 其實是一種程式設計模式 從表裡面查詢資訊而不使用邏輯語句 我的理解是 遇到複雜的邏輯時,考慮把邏輯資料存放到表中,通過查詢表來解決,不用通過寫複雜的 if else來解決,而且這樣迭代性 維護性也好。2.使用表啟動法的兩個問題及解決思路 1 如何去訪問表 1...

程式設計原則 表驅動法

說明這個概念之前最好先給出不使用這個概念的 常見的需要使用表驅動的場景有如下三種情況 場景1 不同條件不同資料 if key key a else if key key b 場景2 不同條件不同行為 if key key a else if key key b 場景3 不同條件依次執行 執行 key...

linux裝置驅動的難點重點

linux裝置驅的學習是一項浩繁的工程 l編寫linux裝置驅動要求工程師有非常好的硬體基礎,懂得sram,flash,sdram,磁碟的讀寫方式,uart,iic,usb等裝置的介面以及輪詢,中斷,dma原理,pci匯流排的工作方式以及cpu的記憶體管理單元 mmu 等。l非常好的c語言基礎,能夠...