現在是我們考慮支持切入點的時候了,結合第三篇中對切入點的討論,在我們的meta_worker類中加入切入點的調用應該不難,只需修改say_hello_closure和meta_worker::getMethod兩個函數即可:
template
struct cut_point_closure {
typedef meta_cut_point
typedef typename my_meta_cut_point::enter_point_args enter_point_args;
typedef typename my_meta_cut_point::leave_point_args leave_point_args;
enter_point_args mEnterPointArgs;
leave_point_args mLeavePointArgs;
mCutPoints[0] = NULL;
mCutPoints[1] = NULL;
mEnterPointArgs.targetArgs = NULL;
mEnterPointArgs.ignoreTarget = false;
mLeavePointArgs.enterPointArgs = &mEnterPointArgs;
mLeavePointArgs.targetRetVal = NULL;
mLeavePointArgs.error = NULL;
}
bool onEnter(meta_worker::object_data * that) {
if (mCutPoints[0]) {
mEnterPointArgs.targetArgs = that;
mCutPoints[0]->closureEntry(&mEnterPointArgs);
}}
~cut_point_closure() {
if (mCutPoints[1])
mCutPoints[1]->closureEntry(&mLeavePointArgs);
};
struct say_hello_cut_point_traits {
typedef meta_worker::object_data arg_type;
typedef void_type ret_type;
};
struct say_hello_closure: cut_point_closure
meta_worker::meta_say_hello::arg_wrapper_type mArgWrapper;
void operator ()(meta_worker::object_data * that) {
onEnter(that);if (!mEnterPointArgs.ignoreTarget) {
mArgWrapper.args.that = that;
mMetaClosure->closureEntry(&mArgWrapper);
}
}
};
bool meta_worker::getMethod(const char * name, void * out_closure, size_t closureSize) {
if ( 0 == strcmp("sayHello", name) && sizeof(say_hello_closure) == closureSize ) {
say_hello_closure * closure = static_cast
closure->mCutPoints[0] = mEnterPoints[1];
closure->mCutPoints[1] = mLeavePoints[1];
closure->mMetaClosure = &mMetaSayHello;
return true;
} else {
// 檢查名字並返回其它函數的閉包...
}
雖然上面的例子並不是最優的實現(有興趣的朋友不妨自己修改看看),但不妨礙我們繼續討論。現在我們終於到了沖刺的時刻,利用切入點,我們可以很方便的在調用sayHello(...) 之前(參見上一篇中的用法示例)的任何地方實現一個切入點處理函數,並將這個函數注冊到 meta_worker 中,通常我們可以利用一個函數來做這件事,然後,我們可以把這個注冊切入點的函數封裝到一個插件(即動態庫)中,這樣,當我們調試時,只需要更新這個插件就能輕松獲得我們想要的日志了。具體的代碼就不再演示了,有需要的朋友可以查閱一些動態庫方面的資料,或者直接給我留言。
到此,我們的第一個例子問題就算解決了,最後還需要再提一點,如果你是一位熟悉設計模式的朋友,你可能認為這裡采用的方法有些麻煩,在解決這個問題時的一個關鍵技術就是對切入點的支持,而利用設計模式中的 Agent 模式也可達到同樣的效果,不是嗎?我要說的是,沒錯,的確如此,這正應驗了一句老話“條條大路通羅馬”,但這裡有兩個事實需要說明:1)切入點的概念本來就來自於元類編程,利用 Agent 模式去實現只是實現方法不同,其思想並沒有變;2)這裡采用的例子只是大多數講元類編程的(其它支持元類編程語言的)文章或書籍中都舉過的例子,這裡無非是為了幫助不了解元類編程的朋友理解元類的正確概念和用法。事實上我們在現實的工作中,還有很多其它的問題,當采用元類編程技術來解決就會方便得多,而這也正是我准備在下篇中重點介紹的內容。