一治拿、前言
原型模式(Prototype Pattern)相對比較簡單足绅,因此并不為其專門開一次研討會捷绑,在閑余時(shí)間自行學(xué)習(xí),接下來我們來看看該模式的具體內(nèi)容氢妈。
二粹污、原型模式
原型模式即實(shí)現(xiàn)一個(gè)原型接口,該接口用于創(chuàng)建當(dāng)前對象的克隆首量。
意圖:用原型實(shí)例指定創(chuàng)建對象的種類壮吩,并且通過拷貝這些原型創(chuàng)建新的對象进苍。
當(dāng)直接創(chuàng)建對象的代價(jià)比較大時(shí),則采用這種模式鸭叙。例如觉啊,一個(gè)對象需要在一個(gè)高代價(jià)的數(shù)據(jù)庫操作之后被創(chuàng)建。我們可以緩存該對象递雀,在下一個(gè)請求時(shí)返回它的克隆柄延,在需要的時(shí)候更新數(shù)據(jù)庫,以此來減少數(shù)據(jù)庫調(diào)用缀程。
原型模式的類圖如下所示:
三搜吧、原型模式在AWTK中的應(yīng)用
由類圖可知,原型模式其實(shí)就是提供一個(gè)克隆接口用于創(chuàng)建對象杨凑,從而規(guī)避構(gòu)造函數(shù)的約束滤奈,也節(jié)省了初始化對象的過程。
在AWTK中撩满,控件基類類 widget_t 便提供了克隆接口 widget_clone()蜒程,那么該接口通常用在什么地方呢?
在 AWTK-MVVM 中動態(tài)更新 list_view 控件便使用了該接口伺帘,代碼如下:
AWTK是 ZLG 開發(fā)的開源 GUI 引擎昭躺,官網(wǎng)地址:https://www.zlg.cn/index/pub/awtk.html。
AWTK-MVVM 是一套為 AWTK 用 C 語言開發(fā)伪嫁,并支持各種腳本語言的 MVVM 框架领炫,GitHub倉庫:http://github.com/zlgopen/awtk-mvvm。
//awtk-mvvm\src\mvvm\awtk\binding_context_awtk.c
......
static widget_t* binding_context_get_widget(binding_context_t* ctx, widget_t* container) {
darray_t* cache = &(ctx->cache_widgets);
widget_t* widget = darray_pop(cache);
if (widget == NULL) {
widget_t* template_widget = WIDGET(widget_get_prop_pointer(container, WIDGET_PROP_TEMPLATE_WIDGET));
//將第一個(gè)子控件作為模板张咳,通過克隆的方式實(shí)現(xiàn)動態(tài)生成子控件帝洪。
widget = widget_clone(template_widget, NULL);
}
return widget;
}
......
static ret_t binding_context_prepare_children(binding_context_t* ctx, widget_t* widget) {
uint32_t i = 0;
view_model_t* view_model = ctx->view_model;
uint32_t items = object_get_prop_int(OBJECT(view_model), VIEW_MODEL_PROP_ITEMS, 0);
widget_t* template_widget = WIDGET(widget_get_prop_pointer(widget, WIDGET_PROP_TEMPLATE_WIDGET));
if (template_widget == NULL) {
template_widget = widget_get_child(widget, 0);
widget_set_prop_pointer(widget, WIDGET_PROP_TEMPLATE_WIDGET, template_widget);
widget_on(widget, EVT_DESTROY, binding_context_on_container_destroy, widget);
widget_remove_child(widget, template_widget);
}
widget_trim_children(ctx, widget, items);
for (i = widget_count_children(widget); i < items; i++) {
widget_add_child(widget, binding_context_get_widget(ctx, widget));
}
return_value_if_fail(items == widget_count_children(widget), RET_OOM);
return RET_OK;
}
......
從以上代碼可以看出,當(dāng) list_view 控件中的子控件需要動態(tài)生成時(shí)脚猾,使用原型模式進(jìn)行克隆時(shí)最簡單的方式葱峡,可以試想如果不使用原型模式,用 widget_factory() 來構(gòu)造每一個(gè)子控件龙助,那么將會出現(xiàn)構(gòu)造砰奕、初始化等臃腫繁瑣的代碼,而且由于 list_view 子控件的相似性提鸟,其中初始化的過程顯得非常多余脆淹。
此處使用原型模式讓代碼可讀性更好,變得更優(yōu)雅沽一,避免了重復(fù)調(diào)用構(gòu)造函數(shù)和初始化子控件對象的過程盖溺,對 AWTK-MVVM 感興趣的朋友可自行查閱源碼。
四铣缠、總結(jié)
4.1 優(yōu)缺點(diǎn)
優(yōu)點(diǎn):
- 性能提高烘嘱。
- 逃避構(gòu)造函數(shù)的約束昆禽。
- 讓代碼變得更優(yōu)雅,可讀性更好蝇庭;
缺點(diǎn):
- 配備克隆方法需要對類的功能進(jìn)行通盤考慮醉鳖,這對于全新的類不是很難,但對于已有的類不一定很容易哮内,特別當(dāng)一個(gè)類引用不支持串行化的間接對象盗棵,或者引用含有循環(huán)結(jié)構(gòu)的時(shí)候。
- 必須實(shí)現(xiàn) Clone 接口北发。
5.1 適用場景
- 當(dāng)一個(gè)系統(tǒng)應(yīng)該獨(dú)立于它的產(chǎn)品創(chuàng)建纹因,構(gòu)成和表示時(shí)。
- 當(dāng)要實(shí)例化的類是在運(yùn)行時(shí)刻指定時(shí)琳拨,例如瞭恰,通過動態(tài)裝載。
- 為了避免創(chuàng)建一個(gè)與產(chǎn)品類層次平行的工廠類層次時(shí)狱庇。
- 當(dāng)一個(gè)類的實(shí)例只能有幾個(gè)不同狀態(tài)組合中的一種時(shí)惊畏。建立相應(yīng)數(shù)目的原型并克隆它們可能比每次用合適的狀態(tài)手工實(shí)例化該類更方便一些。