4/28/2010

Singleton Pattern

Singleton Pattern帶來的是保證一個class只有一個實體,無法產生第二個第三個... 使用這種模式的概念是系統中永遠只會唯一存在,如OS kernal、program core或hardward controller等。C++實作如下:
class IOController {
private:
    IOController() { /*implement*/ }
    IOController(const Core&);
    IOController& operator=(const IOController&);
    virtual ~IOController();

public:
    static IOController& getIOController() {
        static IOController IOController;
        return IOController;
    }

    void memberFunctionA() {}
    void memberFunctionA() {}

private:
    MemberData A;
    MemberData B;
};
一個正確的Singleton應該確保唯一性,C++確保唯一的保護措施有三點:
1. default constructor宣告為private並實作(空內容也沒關係)。因此實體只能在內部產生,外部無法取得建構子。
2. copy constructor and operator=宣告為private並不實作。宣告為private使得外部無法取得函式原型,不實作它是因為不需要,並且令編譯失敗(若使用到copy constructor or operator=,因為沒有實作,會產生連結錯誤,確保不能複製物件)
3. destructor宣告為private,防止外部刪除實體。(這一點可商議。若getIOController()回傳IOController*,則destructor必須宣告為private;若getIOController回傳IOController&,那這點可忽略)

另外值得注意的是getIOController()中宣告static IOController IOController物件,這樣寫法是依賴編譯器的一個規則,"函式內的靜態物件在該函式第一次執行時被初始化",所以getIOController從末被呼叫時,IOController沒有被初始化,效能並沒有降低。

提到唯一性一定會想起靜態函式和靜態物件,那Singleton可以利用靜態來實作嗎
class IOController {
public:
    static void memberFunctionA() {}
    static void memberFunctionA() {}
    // ...

private:
    static MemberData A;
    static MemberData B;
    // ...
};
這樣看似沒甚麼問題,也不需要宣告private之類有的沒的。但是這情況下會缺乏擴充性,假如現在需要第二代IOController2,且保留IOController,視不同情況選擇使用。這樣實作IOController2會很困難,因為靜態函式不能成為虛擬函式,所以IOController和IOController2不能使用多型。若以原來的範例則可以輕鬆解決。
class IOController2 : public IOController {
private:
    IOController2() { /*implement*/ }
    IOController2(const IOController2&);
    IOController2& operator=(const IOController2&);
    virtual ~IOController2();

public:
    static IOController2& getIOController2() {
        static IOController2 IOController2;
        return IOController2;
    }

    void memberFunctionA() {}
    void memberFunctionB() {}

private:
    MemberData C;
    MemberData D;
};
void main {
    bool condition = true;
    Core& core = condition? IOController2::getIOController2(): IOController::getIOController();

    core.memberFunctionA();
    core.memberFunctionB();
}

4/21/2010

陀飛輪

主誯:陳奕迅
作曲:Vincent Chow 填詞:黃偉文
編曲:Gary Tong 監製:Alvin Leong

過去十八歲 沒戴錶 不過有時間
夠我 沒有後顧 野性貪玩

霎眼廿七歲 時日無多 方不敢偷惰
宏願縱未了 奮鬥總不太晚

然後突然今秋
望望身邊 應該有 已盡有
我的美酒 跑車 相機 金錶 也講究
直到世間 個個也妒忌 仍不怎麼富有
用我尚有 換我沒有 其實已用盡所擁有

曾付出 幾多心跳
來換取 一堆堆的發票
人值得 命中減少幾秒 多買一隻錶
秒速 捉得緊了
而皮膚竟偷偷鬆了
為何用到盡了 至知哪樣緊要

勞力是 無止境
活著多好 不需要 靠物證
也不以高薪 高職 高級品 搏尊敬 wo~
就算搏到 伯爵那地位 和蕭邦的雋永
賣了任性 日拼夜拼 忘掉了為甚麼高興

曾付出 幾多心跳
來換取 一堆堆的發票
人值得 命中減少幾秒 多買一隻錶
秒速 捉得緊了
而皮膚竟偷偷鬆了
為何用到盡了 至知哪樣緊要

記住那關於光陰的教訓
回頭走天已暗
你獻出了十吋 時和分
可有換到十吋金

還剩低 幾多心跳
人面跟水晶錶面對照
連自己 亦都分析不了 得到多與少
也許 真的瘋了
那個倒影多麼可笑
靈魂若變賣了 上鏈也沒心跳

銀或金 都不緊要
誰造機芯 一樣了
計劃了 照做了 得到了 時間卻太少 no~

還剩低 幾多心跳
還在數 趕不及了
昂貴是這刻 我覺悟了
在時計裏 看破一生 渺渺

Memento Pattern

Mememto Pattern是一個簡單輕量的模式,基本上它十分簡單,也沒有必要複雜化。故名思義,這種模式是記錄一些回憶,過去資訊,目的是為了備份。在大型軟體中功能複雜而彈性,必定會提供使用者進行設定,在設定途中,總會有使用者想反悔不想執行改變設定,這種模式就是為了取消還原設定而存在的。
class CoreMemento {
    friend class Core;

private:
    CoreMemento() {}
    CoreMemento(const CoreMemento&);
    CoreMemento& operator=(const CoreMemento&);

    // member data
};

class Core {
public:
    // member function, getter/setter function

    CoreMemento getMemento();
    bool recovery(const CoreMemento&);
};

class ConfigDialog {
public:
    ConfigDialog(Core& core) : m_core(core) {
        m_memento = m_core.getMemento();
    }

    void OnCancel() {
        core. recovery(m_backup);
    }

    // member function, setting core function

private:
    Core& m_core;
    CoreMemento m_backup;
};
Memento class的實作如上所示,它沒有成員函式,只有成員變數記錄資料,亦沒有任何資料對外公開,甚至宣告copy constructor和operator=為私有不讓programmer複製物件,只宣告friend class讓Core作存取。因為實際上Memento class的用途只為了記錄Core的資料供還原使用,過多的公開是不必的,還可能誤導programmer認為Memento是可修改的,良好的設計應該在編譯期就檢查出來。

假設ConfigDialog是一個供使用者設定Core的UI介面,當使用者修改途中按取消鍵,會呼叫OnCancel(),這函式就把一開始的CoreMemento提供給Core作還原。

4/17/2010

Policy-Based Class Design

在C++新增template功能的初期,大家普遍認為template只是為物件導向設計得到更好的重用性,不單單將重複使用的程式碼設計成物件類別(class),連類別也重用,經由編譯器幫programmer把不同型別但功能完全相同的程式碼複製。如standard template library裡的vector,宣告vector就是一個存intergerarray的向量,宣告vector就是一個存character pointer array的向量,各自均在insert, earse等功能相同的介面。

其後有意無意間大家發現template能做的事情不單單如此,甚至出乎意料之外的強大,如使用LISP之類的技巧令編譯器幫你在編譯期運算,或編譯期才組合產生你所需要的程式碼。

在大型長期開發的軟體中,保持架構效能延展性介面一致十分重要,可是軟體設計必定不斷變動,功能的擴充、模組的更換尤其繁甚,為了加插功能、修改模組,結果往往就是架構變型,效能降低,介面不一致,元件肥大。(更可怕的是為求擴充,不斷新增介面,混亂不堪,日後維護困難,難以接手)

Policy-Based Class Design是一種新思維的設計方法,藉由template把各種小行為在編譯期組合成為功能複雜的元件,具有高度的效能和彈性。這種設計分為兩部份 ── policies, host class。policies是一些小型的類別,只單純負責某一核心功能,獨立運作的「策略」,如設計模式 (Design Pattern) 中的行為模式 (behavioral pattern) 或結構模式 (structural pattern),而host class像是一個外殼,由多個policies組成,針對特定主題,定義通用介面和錯綜複雜的邏輯流程,核心功能的細節完全經由組合的policies來實現。這種程式設計就像現實生活中的大公司,主管就是host class,為了完成專案找了幾個小將(policies)回來,排行程,分配資源,協調工作,開會擋箭,追殺廠商等,小將只要完成專案裡的需求就好了。(真完美)


現在來看看軟體裡經常會遇到的案例,假設軟體需要存儲設定,一開始決定使用ini格式,因此普遍會寫一個ConfigManager,提供寫入、擷取和操作介面。
class ConfigManager {
public:
    BOOL Load(char* path);
    void Write(char* path);

    BOOL Add(char* columeName, char* columeValue);
    char* columeValue Query(char* columeName);
};
如果考慮到延展性,ConfigManager將會繼承Load()和Write()這兩個單獨功能的類別。但這樣有一個缺點ConfigManager會繼承IniLoader和IniWriter裡所有公開介面,介面被破壞。
class ConfigManager : public IniLoader, public IniWriter {
public:
    BOOL Add(char* columeName, char* columeValue);
    char* columeValue Query(char* columeName);
};

class IniLoader {
public:
    virtual BOOL Load(char* path);
};

class IniWriter {
public:
    virtual BOOL Write(char* path);
};
除了使用多重繼承外,也可使用組合物件方式。
class ConfigManager {
public:
    BOOL Load(char* path) {
        if (IsExist(path))
            m_iniLoader.Load(path);
    }
    void Write(char* path) {
        if (IsExist(path))
            m_iniWriter.Write(path);
    }

    BOOL Add(char* columeName, char* columeValue);
    char* columeValue Query(char* columeName);

private:
    IniLoader m_iniLoader;
    IniWriter m_iniWriter;
};
其後軟體需要更換模組,假設由Ini改為Xml,還需要自動從Ini升級到Xml喔。所以可能會設計抽象類別BaseLoader和BaseWriter,IniLoader, XmlLoader, IniWriter, XmlWriter分別繼承抽象,並傳入ConfigManager中,讓上層去決定使用那種Loader和Writer。
class ConfigManager {
public:
    ConfigManager(BaseLoader* pLoader, BaseWriter* pWriter) {
        m_pLoader = pLoader; m_pWriter = pWriter;
    }

    BOOL Load(char* path) {
        if (IsExist(path))
            m_iniLoader.Load(path);
    }
    void Write(char* path) {
        if (IsExist(path))
            m_iniWriter.Write(path);
    }

    BOOL Add(char* columeName, char* columeValue);
    char* columeValue Query(char* columeName);

private:
    BaseLoader* m_pLoader;
    BaseWriter* m_pWriter;
};

class BaseLoader {
public:
    virtual BOOL Load(char* path) = 0;
};

class BaseWriter {
public:
    virtual BOOL Write(char* path) = 0;
};
現在的設計看起來一切都很好,可怕的事情發生了,針對Xml的讀入處理,ConfigManager需要提供一個介面Fix(),這時介面的一致性就被破壞了,如果使用一開始所說的多重繼承,則必須宣告四個不同的類別才能令介面保持一致性。如果未來還新增網路讀取功能NetLoader, NetWriter,就必須宣告 2 * 2 * 2 個不同類別了,這不就正好是template的能力嗎。

”令軟體存在數種不同版本的設計實作方案,每次只從中選擇其一的方案,而又需要保持切換與擴充的彈性”就是Policy-Based Class Design的中心思想。Policy-Based Class Design的設計如下,ConfigManager是host class,IniLoader, IniWriter, XmlLoader和XmlWriter是policies。
template<class Loader, class Writer>
class ConfigManager : public Loader, public Writer {
public:
    BOOL Load(char* path) {
        if (IsExist(path))
            m_iniLoader.Load(path);
    }
    void Write(char* path) {
        if (IsExist(path))
            m_iniWriter.Write(path);
    }

    BOOL Add(char* columeName, char* columeValue);
    char* columeValue Query(char* columeName);
};

class XmlLoader {
public:
    BOOL Load(char* path);
    BOOL Fix();
};
void main() {
    ConfigManager<Xmlloader, Iniwriter> c1;
    ConfigManager<Iniloader, Xmlwriter> c2;
    ConfigManager<Xmlloader, Netwriter> c3;

    c1.Load("xxx");
    c1.Fix();
    c2.Load("xxx");
    c2.Fix();    // compile error
    c3.Load("xxx");
    c1.Write("xxx");
    c2.Write("xxx");
    c3.Write("xxx");
}
看到這裡總會有點點卡住,到底Polymorphism Design和Policy-Based Class Design有甚麼差別呢。其實兩者之間有著極大的差異,如果說繼承體系是上而下 (top down)構成,介面由Base class定義,由Derived class實作,那麼Policy-Based Class就是下而上 (bottom up)構成,介面由Host class定義,由Policy class實作。Host class會繼承它所需的policies,並且在Host class中定義出操作行為的骨架流程,至於真正的實作細節,則全權委派 (delegate)給policies進行處理。架構恰好完全與繼承體系方向相反

上述例子中還不算最終形式的Policy-Based Class Design,就像遞迴一樣的概念,tempate也可以是多層的,經由Host class傳遞template parameter給polices來逹到,能組合出更多的功能。(這種組合可是次方級數成長的喔),如下,現在不再統一一起寫設定檔,改為每個元件單獨讀寫。
template<class Loader, class Writer, class Componet>
class ConfigManager : public Loader<Componet>, public Writer<Componet> {
public:
    BOOL Load(char* path) {
        if (IsExist(path))
            m_iniLoader.Load(path);
    }
    void Write(char* path) {
        if (IsExist(path))
            m_iniWriter.Write(path);
    }

    BOOL Add(char* columeName, char* columeValue);
    char* columeValue Query(char* columeName);
};

template<class Componet>
class IniLoader {
public:
    BOOL Load(char* path) {
        Componet::GetConfigInfo();
        // do something
    }
};
void main() {
    ConfigManager<XmlLoader, IniWriter, Schedular> c1;
    ConfigManager<IniLoader, XmlWriter, Recorder> c2;
    ConfigManager<IniLoader, NetWriter, RemoteServer> c3;

    c1.Load("xxx");
    c1.Fix();
    c2.Load("xxx");
    c2.Fix();    // compile error
    c3.Load("xxx");
    c1.Write("xxx");
    c2.Write("xxx");
    c3.Write("xxx");
}
說穿了Policy-Based Class Design的基本原理就是Strategy Pattern,如果現在需要的策略只有一個,那整個Host class就跟Strategy Pattern十分類似,也沒有必要使用Policy Design了。但是,如果現在需要的策略是兩個以上,還繼續使用Strategy Pattern反而會降低效能,元件肥大,日後難以維護。而Policy-Based Class Design就是使用template幫你組合程式碼,把多個Strategy Pattern組合成為一個類別,同時減低設計的相依性。

總結一下Policy-Based Class Design的優缺處
1. 高顆粒性 (granularity),核心功能獨立運作,方便unit test。
2. 高延展性。只要架構不變,新增功能、更換模組和小修改,只要寫Policy class就可以了。
3. 高擴充性。這是進階主題,下回再說。
4. 介面一致。每一個ConfigManger有一致的共用介面,定義在Host class裡,同時,對於特定某種ConfigManager能從繼承中獲得額外的介面,別與其他ConfigManager,又能保持介面完整。
5. 介面高彈性。這是進階主題,下回再說。
6. 高效能。每一個ConfigManager的介面和實作由繼承而來,避免透過成員變數中的抽象類別間接呼叫。值得注意的是Host, Policy class基本上是不用(也不需要)虛擬函式,直接免除virtual table的間接呼叫和記憶體使用量。
7. Host class實作技巧高。Host class使用到template,比直接寫一般的C++難。
8. 實作思想需要改變。Policy class非常獨立,常常是沒有任何成員變數,只實作行為,資料由參數傳入,回傳結果。

12/11/2009

Invoke pure virtual function

沒錯 你沒看錯
這篇的標題是呼叫純虛擬函式
一個沒有實作的純虛擬函式是有可能被呼叫起來的
class A {
public:
    virtual void f(void) = 0;
};
class B : public A {
    virtual void f(void) {}
};
在系統開發中 這是一個很常出現的程式片斷
在多型體系中
A* a = new B;
a->f();
因為vtable的存在 程式會為f找尋合適的function pointer並呼叫
這例子中從vtable中會找到class B中的f()
這並沒有甚麼問題
那麼如果vtable中沒有class B的資訊時會怎麼樣 那就會找到class A的f()
就會呼叫純虛擬函式了

這會發生嗎?
會的
class A;
class A {
public:
    virtual ~A() { m_pA->Close(); }
    virtual void Close(void) = 0;
    A* m_pA;
};
class B : public A {
    virtual void Close(void) {}
};
像這樣的程式
一般人會想說把所有的CloseXXX, DeleteXXX, DestoryXXX寫在解構子
解構子被呼叫的順序是從下而上
所以B的解構子先呼叫 把vtable清掉
A的解構子再呼叫 這時vtable中只有class A 所以就呼叫一個純虛擬函式了

當然 Effective C++裡提到 不應該在解構子呼叫虛擬函式 會有類似的問題出現
而在多執行緒中 也可能發生
class B : public A {
    virtual void f(void) {}
    void ThreadProc() {
        while(1)
            f();
    }
};

void main() {
    A* a = new B();

    while(1) {
        if (...)
            a->Create();
        if (exception == true)
            break;
    }
    delete a;
}
我們把class B改為一個thread 它會不斷的呼叫f()
當一個執行緒因為例外發生或其他原因 使物件的解構子被呼叫
呼叫到一半的時候 另一個執行緒呼叫該物件的虛擬函式
剛好解構到vtable只剩下Base class時 就會呼叫純虛擬函式了

11/19/2009

說謊

主唱:林宥嘉
詞:施人誠
曲:李雙飛

是有過幾個不錯對象 說起來並不寂寞孤單
可能我浪蕩 讓人家不安
才會 結果都陣亡

我沒有什麼陰影魔障 妳千萬不要放在心上
我又不脆弱 何況那算什麼傷
反正愛情不就都這樣

我沒有說謊 我何必說謊
妳懂我的 我對妳從來就不會假裝
我哪有說謊
請別以為妳有多難忘 笑是真的不是我逞強

我好久沒來這間餐廳 沒想到已經換了裝潢
角落那窗口 聞得到玫瑰花香
被妳一說是有些印象

我沒有說謊 我何必說謊
妳知道的 我缺點之一就是很健忘
我哪有說謊
是很感謝今晚的相伴 但我竟然有些不習慣

我沒有說謊 我何必說謊
愛一個人 沒愛到難道就會怎麼樣
別說我說謊
人生已經如此的艱難 有些事情就不要拆穿

我沒有說謊 是愛情說謊
它帶妳來 騙我說 渴望的有可能有希望
我沒有說謊
祝妳做個幸福的新娘 我的心事請妳就遺忘

7/28/2009

C/C++ with MySQL

最近一直找一個bug 找很久都找不出來

狀況是這樣子

在一台linux上裝上 MySQL 5.0, Apache 2.0, django 1.0, openssl 5.5.2

建立一台有網頁 有cgi 有ssl的平台

之後複製另一台成master and slave 同時使用 MySQL Replication

令兩台資料庫保持一致狀態 作為master掛掉時自動起來的back up server

問題來了 它們總是不一致

測了很久發現我c++的cgi使用Connector/C++ 1.0 Preview來連接MySQL 但不會產生MySQL的binary log

沒有binary log就沒辨法使用MySQL Replication

後來

花了個晚上把Connector/C++換成MySQL++


看來兩套功能相同的東西 還是選版本比較大的好 = ="

7/27/2009

摸索

半年來
每天不斷的上班 上班 除了上班還剩甚麼
每天趨於平淡 盲目
我想要的生命似乎漸漸地從手中流失
就這樣嗎?
我的生活需要點不一樣的 需要點衝擊

7/25/2009

The Show

http://www.youtube.com/watch?v=hnN30rs5NkQ
十分值得聽的歌 澳洲的創作女歌生 lenka
The Show

I'm just a little bit
caught in the middle
Life is a maze
and love is a riddle
I don't know where to go
I can't do it alone
(I've tried)
and I don't know why
its cuz jollys cool

Slow it down
make it stop
or else my heart is going to pop
'cuz it's too much
Yeah, it's a lot
to be something I'm not

I'm a fool
out of love
'cuz I just can't get enough

I'm just a little bit
caught in the middle
Life is a maze
and love is a riddle
I don't know where to go
I can't do it alone
(I've tried)
and I don't know why

I am just a little girl
lost in the moment
I'm so scared
but I don't show it
I can't figure it out
it's bringing me down
I know
I've got to let it go
and just enjoy the show

The sun is hot
in the sky
just like a giant spotlight
The people follow the sign
and synchronize in time
It's a joke
Nobody knows
they've got a ticket to that show
Yeah

I'm just a little bit
caught in the middle
Life is a maze
and love is a riddle
I dont know where to go
I can't do it alone
(I've tried)
and I don't know why

I am just a little girl
lost in the moment
I'm so scared
but don't show it
I can't figure it out
it's bringing me down
I know
I've got to let it go
and just enjoy the show

oh oh
Just enjoy the show
oh oh

I'm just a little bit
caught in the middle
life is a maze
and love is a riddle
I dont know where to go
I can't do it alone
(I've tried)
and I don't know why

I am just a little girl
lost in the moment
I'm so scared
but I don't show it
I can't figure it out
it's bringing me down
I know
I've got to let it go
and just enjoy the show

dum de dum
dudum de dum

Just enjoy the show

dum de dum
dudum de dum

Just enjoy the show

I want my money back
I want my money back
I want my money back
Just enjoy the show

I want my money back
I want my money back
I want my money back
Just enjoy the show

12/09/2008

you and i both

演唱:jason mraz

Was it you who spoke the words that things would happen but not to me?
All things are gonna happen naturally
Oh, taking your advice and I'm looking on the bright side
And balancing the whole thing.

Oh, but at often times those words get tangled up in a lines
And the bright light turns to night
Oh, until the dawn it brings
Another day to sing about the magic that was you and me

Cause you and I both loved
What you and I spoke of
And others just read of
Others only read of, of the love
Of the love that I loved

lova lova!

See I'm all about them words
Over numbers, unencumbered numbered words;
Hundreds of pages, pages, pages for words.
More words than I had ever heard, and I feel so alive.

Cause you and I both loved
What you and I spoke of
And others just read of
And if you could see me now
Oh, love love
You and I, You and I
Not so little you and I anymore

And with this silence brings a moral story
More importantly evolving is the glory of a boy

Cause you and I both loved
What you and I spoke of (of, of)
And others just read of
And if you could see me now
Well, then I'm almost finally out of
I'm finally out of
Finally deedeedeedeedeedee
Well I'm almost finally, finally
Well I am free
Oh, I'm free

And it's okay if you had to go away
Oh, just remember that telephones
Well, they work out of both ways
But if I never ever hear them ring
If nothing else I'll think the bells inside
Have finally found you someone else and that's okay
Cause I'll remember everything you sang

Cause you and I both loved
What you and I spoke of (of,)
And others just read of
and if you could see me now
Well, then I'm almost finally out of
I'm finally out of
Finally deedeedeedeedeede
Well I'm almost finally, finally
Out of words