欧美性猛交XXXX免费看蜜桃,成人网18免费韩国,亚洲国产成人精品区综合,欧美日韩一区二区三区高清不卡,亚洲综合一区二区精品久久

打開(kāi)APP
userphoto
未登錄

開(kāi)通VIP,暢享免費電子書(shū)等14項超值服

開(kāi)通VIP
Strategy模式的C實(shí)現

http://tonybai.com/2011/10/20/implement-strategy-pattern-in-c/

2011

與那些復雜的模式相比,Stragegy Pattern(策略模式)是一個(gè)相對簡(jiǎn)單的模式,很直觀(guān),也易于理解。 同時(shí)它也是我們在開(kāi)發(fā)過(guò)程中使用最多的模式之一。

問(wèn)題是設計模式使用的驅動(dòng)力,只有當我們遇到問(wèn)題時(shí),設計模式才會(huì )向我們伸出援助之手。這里我也想通過(guò)對問(wèn)題以及解決方法演化的闡述來(lái)說(shuō)明策略模式是如何更好地幫助我們的。我們從問(wèn)題出發(fā)!

Tony最近接到了一個(gè)新任務(wù),任務(wù)的內容是實(shí)現一個(gè)通用的平衡二叉樹(shù)數據結構供其他同事使用。接到這個(gè)任務(wù)后,他十分欣喜,因為在之前的工作中他一直在用C語(yǔ)言編寫(xiě)繁蕪復雜的業(yè)務(wù)邏輯,這讓他感覺(jué)很煩躁。今天他終于盼到了一個(gè)做公共庫的機會(huì )。為此Tony連夜拜讀了《C語(yǔ)言接口與實(shí)現》一書(shū),希望能從書(shū)中取點(diǎn)經(jīng),做出一個(gè)讓大家都滿(mǎn)意的通用的平衡二叉樹(shù)。

Tony十分欣賞《C語(yǔ)言接口與實(shí)現》中采用的一些原則,比如盡量隱藏細節,只給外部暴露必要的信息等。他也是按照書(shū)中的原則來(lái)定義平衡二叉樹(shù)的各個(gè)操作接口的。但在定義接口的過(guò)程中Tony卻遇到了問(wèn)題,以平衡二叉樹(shù)的創(chuàng )建和銷(xiāo)毀接口為例,Tony最初設計的接口原型是這樣的:

/* balanced_binary_tree.h */
… …
struct bb_tree_t;
int bb_tree_create(struct bb_tree_t **tree, …);
int bb_tree_destroy(struct bb_tree_t **tree, …);
… …

/* balanced_binary_tree.c */
struct bb_tree_t {
    …
};
… …

很顯然,為了隱藏細節,Tony選擇了在接口實(shí)現內部為tree分配和釋放內存空間,但他不確定應該用哪種內存分配方式。他經(jīng)過(guò)一番思維斗爭后最終選擇了使用標準庫中的malloc和free,因為他堅定地認為多數人都會(huì )使用這套標準的內存管理接口,例外的可能性很小。后續的實(shí)現過(guò)程很順利,當這套"設計優(yōu)美"的平衡二叉樹(shù)公共庫被提交給其他同事使用時(shí),Tony感覺(jué)十分地開(kāi)心。

/* balanced_binary_tree.c */
int bb_tree_create(struct bb_tree_t **tree, …) {
    struct bb_tree_t *p = (struct bb_tree_t*)malloc(sizeof(*p));
    …
}

int bb_tree_destroy(struct bb_tree_t **tree, …) {
    free(*tree);
    … …
}

不過(guò)墨菲定律告訴我們:事情如果有變壞的可能,不管這種可能性有多小,它總會(huì )發(fā)生。果然好景不長(cháng),這一天一位同事找到了Tony并向他訴苦到:"我們需要在共享內存上使用平衡二叉樹(shù),但你提供的bb_tree只能在堆上分配內存,無(wú)法被多個(gè)進(jìn)程共享,我們真不知道該怎么辦了,不知道你能否修改一下你提供的庫,讓它也支持在共享內存上分配呢"。Tony是個(gè)自尊心很強的人,聽(tīng)到自己提供的公共庫有缺陷,他的心中只有一個(gè)念頭:盡快解決這個(gè)問(wèn)題!

Tony回到座位上開(kāi)始重新審視自己的設計,他滿(mǎn)腦子都是"既要支持標準內存分配接口,又要支持在共享內存上分配"的需求。在考量了十幾分鐘后,他似乎知道該怎么做了,他在屏幕上敲下了如下代碼:

/* balanced_binary_tree.h */
… …
struct bb_tree_t;
enum mem_allocator_flag {
    STD_ALLOCATOR,
    SHM_ALLOCATOR
};
int bb_tree_create(struct bb_tree_t **tree, enum mem_allocator_flag flag, …);
int bb_tree_destroy(struct bb_tree_t **tree, …);
… …

/* balanced_binary_tree.c */
struct bb_tree_t {
    …
    enum mem_allocator_flag flag;
};

int bb_tree_create(struct bb_tree_t **tree, enum mem_allocator_flag flag, …) {
    … …
    struct bb_tree_t *p
    if (flag == STD_ALLOCATOR)
        p = (struct bb_tree_t*)malloc(sizeof(*p));
   
    if (flag == SHM_ALLOCATOR)
        p = (struct bb_tree_t*)shm_malloc(sizeof(*p));

    p->flag = flag;
    … …
}

int bb_tree_destroy(struct bb_tree_t **tree, …) {
    … …
    if ((*tree)->flag == STD_ALLOCATOR)
        free(*tree);
   
    if ((*tree)->flag == SHM_ALLOCATOR)
        shm_free(*tree);
    … …
}

嗯,這樣改后就應該支持在共享內存上分配平衡二叉樹(shù)了。Tony似乎又恢復了信心,表情也不再那么死板嚴肅了!他伸伸懶腰,感覺(jué)有些疲倦,于是他決定趴在辦公桌上小憩一會(huì )兒?;秀敝幸粋€(gè)同事來(lái)到了他的跟前,對他說(shuō):"Tony,標準內存分配接口使用的內存分配算法效率太低,時(shí)間長(cháng)了又會(huì )導致太多的內存碎片,完全不能滿(mǎn)足我們的需求,我們希望能在平衡二叉樹(shù)中使用我們自己實(shí)現的一套高性能內存分配接口,你必須盡快做出修改,不然…."。Tony瞬間從夢(mèng)中驚醒,他努力地回憶了一下剛才夢(mèng)中的情景,又看了看屏幕上剛剛修改過(guò)的代碼,心生一絲竊喜,"還好這只是一場(chǎng)夢(mèng),否則這份代碼又要被人嘲笑了。內存管理的接口有N多種,我總不能每支持一種新分配算法就重新發(fā)布一次吧"。Tony又一次陷入了沉思。不過(guò)這次沉思顯然也沒(méi)有持續多久,Tony似乎又找到了解決方案,屏幕上的代碼發(fā)生了變化。

/* balanced_binary_tree.h */
… …
struct bb_tree_t;
int bb_tree_create(struct bb_tree_t **tree,
                   void (*malloc_func)(size_t size),
                   void (*free_func)(void *ptr), …);
int bb_tree_destroy(struct bb_tree_t **tree, …);
… …

/* balanced_binary_tree.c */
struct bb_tree_t {
    …
    void (*malloc_func)(size_t size),
    void (*free_func)(void *ptr)
};

int bb_tree_create(struct bb_tree_t **tree,
                   void (*malloc_func)(size_t size),
                   void (*free_func)(void *ptr), …) {
    struct bb_tree_t *p = (struct bb_tree_t*)malloc_func(sizeof(*p));
    p->malloc_func = malloc_func;
    p->free_func = free_func;
    … …
}

int bb_tree_destroy(struct bb_tree_t **tree, …) {
    (*tree)->free_func(*tree);
    … …
}

這回Tony把使用何種存儲分配機制的權力完完全全地交給了庫的使用者,這樣縱使內存分配機制有千般變化,這里也依舊可以滿(mǎn)足。不過(guò)這次Tony還是長(cháng)了個(gè)心眼兒,沒(méi)有馬上將庫發(fā)布給其他同事,而是從優(yōu)秀代碼設計的角度再次對自己的代碼做了一次分析。

Tony暫時(shí)拋開(kāi)了bb_tree,而是從所有類(lèi)似的公共庫的設計和實(shí)現角度考慮了許久。他發(fā)現如果公共庫的設計都遵循將細節隱藏,只暴露必要信息的原則的話(huà),勢必都會(huì )遇到類(lèi)似的如何在內部進(jìn)行存儲分配的問(wèn)題。bb_tree使用到了malloc和free接口,但其他公共庫很可能還會(huì )用到calloc、realloc等接口。一旦遇到這種情況,按照上面的方案就會(huì )出現類(lèi)似下面的函數原型形式:

int xx_create(…,
              void (*malloc_func)(size_t size),
              void (*calloc)(size_t nmemb, size_t size),
              void (*realloc)(void *ptr, size_t size),
              void (*free_func)(void *ptr)…);

Tony意識到這個(gè)函數原型參數太多,使用不便,代碼味道自然不好!應該重構一下,將變化的事物封裝起來(lái)。綜上來(lái)看,目前主要有兩點(diǎn)易變的地方:
1) 內存分配接口需支持可替換
2) 不同公共庫可能使用不同形式的內存分配接口,有的用符號malloc原型的,有的用符合calloc原型的。

"封裝變化!",Tony潛意識里跳出的第一個(gè)想法。于是十幾分鐘過(guò)后他的電腦屏幕上就出現了下面這些代碼:

/* mem_allocator.h */
struct mem_allocator_t {
    void (*malloc)(struct mem_allocator_t *allocator, size_t size),
    void (*calloc)(struct mem_allocator_t *allocator, size_t nmemb, size_t size),
    void (*realloc)(struct mem_allocator_t *allocator, void *ptr, size_t size),
    void (*free)(struct mem_allocator_t *allocator, void *ptr)
};

/* balanced_binary_tree.h */
#include "mem_allocator.h"
… …
struct bb_tree_t;
int bb_tree_create(struct bb_tree_t **tree,
                   const struct mem_allocator_t *allocator, …);
int bb_tree_destroy(struct bb_tree_t **tree, …);
… …

/* balanced_binary_tree.c */
struct bb_tree_t {
    …
    const struct mem_allocator_t *allocator;
};

int bb_tree_create(struct bb_tree_t **tree,
                   struct mem_allocator_t *allocator, …) {
    struct bb_tree_t *p = (struct bb_tree_t*)(allocator->malloc(allocator, sizeof(*p)));
    p->allocator = allocator;
    … …
}

int bb_tree_destroy(struct bb_tree_t **tree, …) {
    struct mem_allocator_t *allocator = (*tree)->allocator;
    allocator->free(allocator, *tree);
    … …
}

Tony封裝出一個(gè)接口mem_allocator_t,bb_tree的創(chuàng )建和銷(xiāo)毀只依賴(lài)于mem_allocator_t。我們可以為bb_tree_create傳入不同的mem_allocator_t接口的實(shí)現,以支持內存分配機制的更換;另外mem_allocator_t內部封裝了所有形式的通用的內存管理原型,可以滿(mǎn)足其他公共庫實(shí)現的需要。

面向對象語(yǔ)言可以通過(guò)繼承(derive)接口、重寫(xiě)方法(override method)的方式實(shí)現一個(gè)接口,但在C中,我們只能像下面這樣給出mem_allocator_t接口的一個(gè)實(shí)現 – shm_mem_allocator:

/* shm_mem_allocator.h */
#include "mem_allocator.h"

struct mem_allocator_t* shm_mem_allocator_new();
void shm_mem_allocator_free(struct mem_allocator_t **allocator);

/* shm_mem_allocator.c */

struct shm_mem_allocator_t {
    struct mem_allocator_t allocator;
    … … /* 其他用于實(shí)現shm_mem_allocator所需要的字段 */
};

struct mem_allocator_t* shm_mem_allocator_new() {
    struct shm_mem_allocator_t *allocator = (struct shm_mem_allocator_t*)malloc(sizeof(*allocator));
    if (!allocator)
        return NULL;
    memset(allocator, 0, sizeof(*allocator));

    allocator->allocator.malloc = shm_mem_alloc;
    allocator->allocator.calloc = shm_mem_calloc;
    allocator->allocator.realloc = shm_mem_realloc;
    allocator->allocator.free = shm_mem_free;
   
    return (struct mem_allocator_t*)allocator;
}

static void* shm_mem_malloc(struct mem_allocator_t *allocator, size_t size) {
    struct shm_mem_allocator_t *p = (struct shm_mem_allocator_t*)allocator;
    … …
}

static void* shm_mem_calloc(struct mem_allocator_t *allocator, size_t nmemb, size_t size) {
    struct shm_mem_allocator_t *p = (struct shm_mem_allocator_t*)allocator;
    … …
}

static void* shm_mem_realloc(struct mem_allocator_t *allocator, void *ptr, size_t size) {
    struct shm_mem_allocator_t *p = (struct shm_mem_allocator_t*)allocator;
    … …
}

static void shm_mem_free(struct mem_allocator_t *allocator, void *ptr) {
    struct shm_mem_allocator_t *p = (struct shm_mem_allocator_t*)allocator;
    … …
}

void shm_mem_allocator_free(struct mem_allocator_t **allocator) {
    struct shm_mem_allocator_t *p = (struct shm_mem_allocator_t*)(*allocator);
    free(p);
    (*allocator) = NULL;
}

注意shm_mem_allocator本身也涉及到內部實(shí)現的內存分配問(wèn)題,但考慮到其自身的特質(zhì):我們無(wú)須在共享內存上創(chuàng )建mem_allocator實(shí)例對象,也無(wú)須為mem_allocator實(shí)例對象內部的內存分配算法性能擔憂(yōu)(只是初始化時(shí)使用一次),因此可以無(wú)須支持多種內存分配接口,利用標準內存分配接口足矣。

下面是將bb_tree與shm_mem_allocator結合在一起使用的代碼:
struct bb_tree_t *tree;
ret = bb_tree_create(&tree, shm_mem_allocator_new(), …);
… …

如果你要更換bb_tree內部的內存分配器,則在調用bb_tree_create時(shí)換用你自己的mem_allocator_t接口實(shí)現即可:
struct bb_tree_t *tree;
ret = bb_tree_create(&tree, your_mem_allocator_new(), …);
… …

Tony終于找到了一份可以讓自己滿(mǎn)意的方案了。在發(fā)布代碼庫后,他再也沒(méi)有收到來(lái)自同事們的抱怨之聲。在接下來(lái)的一個(gè)星期里,Tony又用同樣的設計方案讓產(chǎn)品可以支持從多種數據庫(Oracle、MySQL、Sqlite3等)讀取數據。

后來(lái),Tony在翻閱《設計模式》一書(shū)時(shí),發(fā)現自己的解決方法與書(shū)中描述的“策略模式”甚為類(lèi)似,簡(jiǎn)直就是用C語(yǔ)言實(shí)現的策略模式,而且這種模式幾乎沒(méi)有什么缺點(diǎn),除了每增加一種策略(比如新增一種mem_allocator_t接口的實(shí)現),就要多維護一種策略的代碼,但這樣帶來(lái)的負擔與之前相比幾乎是可以忽略不計的。

2011, bigwhite. 版權所有.

0

Related posts:

  1. 一次函數設計討論
  2. Observer模式的C實(shí)現
  3. iterator的C實(shí)現
  4. 償還N年前的一筆技術(shù)債
  5. 使用C99特性簡(jiǎn)化代碼編寫(xiě)
本站僅提供存儲服務(wù),所有內容均由用戶(hù)發(fā)布,如發(fā)現有害或侵權內容,請點(diǎn)擊舉報。
打開(kāi)APP,閱讀全文并永久保存 查看更多類(lèi)似文章
猜你喜歡
類(lèi)似文章
淺談C中的malloc和free
內存管理 - 動(dòng)態(tài)開(kāi)辟內存
模擬內存動(dòng)態(tài)分配學(xué)習
內存管理內幕
C++常用庫函數atoi,itoa,strcpy,strcmp,malloc,free的實(shí)現
lwip之內存管理
更多類(lèi)似文章 >>
生活服務(wù)
分享 收藏 導長(cháng)圖 關(guān)注 下載文章
綁定賬號成功
后續可登錄賬號暢享VIP特權!
如果VIP功能使用有故障,
可點(diǎn)擊這里聯(lián)系客服!

聯(lián)系客服

欧美性猛交XXXX免费看蜜桃,成人网18免费韩国,亚洲国产成人精品区综合,欧美日韩一区二区三区高清不卡,亚洲综合一区二区精品久久