• 沒有找到結果。

第六章 模糊控制器的軟體模式策略

6.2 模糊變數類別

//續上頁程式碼

void SetLambdaTypeFunc(string FuncName, double lzero, double mone, double rzero); //修正 LambdaType 歸屬函數 private:

map<string, BaseFunc*> m_FuncMap; //記錄擁有的歸屬函數 string m_FuzzyValueName; //記錄此模糊變數的名稱

double m_min; //模糊變數範圍最小值 double m_max; //模糊變數範圍最大值 };

此類別的宣告有幾個地方在此說明一下,第一個是負責新增歸屬函數 的 CreateFunc 成員函式中,參數列的第一個參數型別 TypeID,此型 別是自定而來的,自定的方式如下:

typedef int TypeID;

其實 TypeID 型別也就是整數(int)型別,而 CreateFunc 函式第一個 參數所要接受的整數範圍由 1 到 4,分別代表四種歸屬函數,這 1 到 4 分別被如下定義:

#define ZTYPE 1

#define STYPE 2

#define PITYPE 3

#define LAMBDATYPE 4

之所以如此定義,是為了要在使用 CreateFunc 函式時,看起來較為直 觀,比較如下:(註:先不管回傳值)

FuzzyValue aValue;

aValue.CreateFunc(1, “VeryBig”, 0, 100); //新增 ZType 歸屬函數,名稱為 VeryBig

//範圍由 0 到 100 aValue.CreateFunc(ZTYPE, “VeryBig”, 0, 100); //新增同上的歸屬函數

上述的兩行新增歸屬函數的程式碼最後完成的目的雖相同,但是參數

列上,第一行的“1”很難讓人理解,而第二行的“ZTYPE”則很讓 人能夠理解是在新增一個 Z-Type 型的歸屬函數,而這樣突然冒出來 的字面常數(literal constant),我們總是以“megic number”來稱呼 之,來表示看不出意義的字面常數

第二個則是專門負責“收集”歸屬函數的 map 型別變數

m_FuncMap。所謂的 map,是一種聯合容器(associative container),

與之相對就即是循序容器( sequence container)。所謂的循序容器放置 的是一個有序而型別一致的元素集,vector(本論文將使用它)和 list 是兩個主要的循序容器。

vector 表現出的是一塊連續的記憶體空間,所有元素一個接一個 地儲存在裡頭。對一個 vector 做隨機存取(例如存取元素 5,然後元 素 15、然後元素 7 等等)效率很好,因為每一次存取都是抓取從 vector 起頭的固定偏移位置。但是若將新元素安插在 vector 尾部以外的任何 位置,效率便會很差,因為被插入的元素的右側每一個元素都必須做 拷貝的動作。同理,刪除 vector 最後一個元素以外的任何一個元素,

也很沒有效率,因為被刪除的元素的右側每一個元素也都必須做拷貝 動作。

List 表現的是一塊不連續的記憶體空間,利用一對雙向指標指出 前後元素,因此允許向前或向後移動。其任何位置上的元素安插動作

的刪除動作,都很有效率,當然指標會被重新的指定,但是也就沒有 任何元素需要以拷貝的方式來進行移動。和 vector 相反的,list 對於 隨機存取就沒有什麼好支援了,存取一個元素之前,必須先在介於兩 端之間的各個元素上移動。此外,每個元素必須因需要儲存前後的指 標,在空間上是一個額外負擔。

聯合容器支援高效率的元素查詢動作。map 和 set(本論文不討 論)是兩個主要的聯合容器。Map 是一種鍵值/實值(key/value)的 配對,鍵值用來查詢,實值則內含我們希望運作的資料。例如,電話 簿就很適合以 map 來完成,個人稱做為鍵值,電話號碼則做為相應 的實值。

回到 FuzzyValue 類別,收集歸屬函數的資料成員是 m_FuncMap,它的型別宣告如下:

map<string, BaseFunc*> m_FuncMap;

在使用 map 之前,必須包含 STL(Standard Template Library,標準函 式庫)中的 map 標頭檔:

#include<map>

m_FuncMap 的型別是 map,什麼樣的 map 呢? 它的第一個型別參數 為 string,指的是鍵值(key)的型別。第二個參數為實值(value)的 型別,在此是 BaseFunc 類別指標。

之所以要如此宣告,是因為每一個歸屬函數都有其名稱,如“很 大”、“較高”之類的形容詞來表示歸屬函數所要形容的模糊集合,

以下是 FuzzyValue 類別中,成員函式 AddFunc 的實作部份:

void FuzzyValue::AddFunc(BaseFunc* Func) {

m_FuncMap[Func->GetFuncName()] = Func;

}

當 AddFunc 收到一個 BaseFunc 類別指標時,除了將它加入至 m_FuncMap 之中,另外也在同時指定了一個鍵值給它,而代表加入 的 BaseFunc 類別指標變數 Func 呼叫它的成員函式 GetFuncName,回 傳此歸屬函數的名稱來當成指實值的鍵值。

圖 5-6 為目前為此,BaseFunc 類別、ZType 類別、SType 類別、

PiType 類別、LambdaType 類別和剛才的 FuzzyValue 類別之間以 UML 來表示:(如圖 6-6)

1 << aggregation>> *

BaseFunc

ZType

SType

PiType

LambdaType FuzzyValue

在 FuzzyValue 類別與 BaseFunc 類別之間表示“聚合”( aggregation)

的箭頭兩端,一端是“1”,另一端則是“*”,是表示“一個 FuzzyValue 類別的物件,可以“聚合”無限量的 BaseFunc 類別的物 件,而空心菱形的位置則指聚合母體端。