乡下人产国偷v产偷v自拍,国产午夜片在线观看,婷婷成人亚洲综合国产麻豆,久久综合给合久久狠狠狠9

  • <output id="e9wm2"></output>
    <s id="e9wm2"><nobr id="e9wm2"><ins id="e9wm2"></ins></nobr></s>

    • 分享

      如何寫好C代碼之依賴注入

       InfoRich 2019-02-28

      依賴注入(Dependency Injection 簡(jiǎn)寫為DI)開發(fā)過(guò)程中解除耦合的經(jīng)典手段,但是似乎從一開始這貨就是為面向?qū)ο蠖模宜吹降氖纠紱](méi)有將C語(yǔ)言考慮在內(nèi)。難道C語(yǔ)言不能使用這么經(jīng)典的設(shè)計(jì)模式?本文就來(lái)介紹一下C語(yǔ)言如實(shí)使用依賴注入來(lái)解除耦合。

      參數(shù)注入

      對(duì)應(yīng)于面向?qū)ο笳Z(yǔ)言的構(gòu)造函數(shù)注入,C語(yǔ)言作為過(guò)程語(yǔ)言,參數(shù)注入法是最簡(jiǎn)單、也是最直接的方法。最常見的排序方法qsort就是用這種方法:

      void qsort(void* base, size_t num, size_t size, int (*compar)(const void*,const void*));

      可以看到qsort函數(shù)的第四個(gè)參數(shù)compar就是外部依賴的對(duì)象(函數(shù)),因?yàn)椴煌瑘?chǎng)景有不同的比較元素大小的方式,通過(guò)參數(shù)將外部依賴注入,使該函數(shù)更加具有通用型,因?yàn)閷?shí)際上我們用qsort,只是用他的排序算法,其他的都是和具體使用場(chǎng)景有關(guān)。

      設(shè)置(set)接口注入

      上一篇我們介紹的設(shè)置回調(diào)函數(shù)的方法其實(shí)就是使用這種方法,其本質(zhì)就是專門對(duì)外提供一個(gè)接口,用來(lái)將依賴的外部對(duì)象或者函數(shù)注入到本模塊中來(lái)。比如開發(fā)一個(gè)模塊,需要申請(qǐng)內(nèi)存,但是為了易用性,除了使用系統(tǒng)自帶的內(nèi)存申請(qǐng)函數(shù),我們需要支持第三方的內(nèi)存池模塊來(lái)申請(qǐng)內(nèi)存,我們就可以提供一個(gè)API來(lái)設(shè)置申請(qǐng)釋放內(nèi)存的函數(shù),如下示例:

      ///默認(rèn)申請(qǐng)內(nèi)存方式為系統(tǒng)自帶的函數(shù)static void *(*malloc_function)(size_t size) = malloc;static void (*free_function)(void *p) = free;int sample_module_init(){ return 0; }///設(shè)置新的分配內(nèi)存的函數(shù)int sample_module_set_memory_api(void *(*get)(size_t size), void(*put)(void *p)){ malloc_function = get; free_function = put;  return 0;}///申請(qǐng)一個(gè)size大小的int類型數(shù)組int *sample_module_create_int_array(size_t *size){ int *p = (int *)malloc_function(sizeof(int) * size); return p;}

      這樣我們?cè)谑褂眠@個(gè)模塊時(shí),就可以設(shè)置三方的內(nèi)存申請(qǐng)方式了。比如想使用jemalloc的內(nèi)存分配方式,調(diào)用sample_module_set_memory_api 將內(nèi)存分配的函數(shù)指針設(shè)置為該庫(kù)的內(nèi)存申請(qǐng)API就可以了。

      sample_module_set_memory_api(mallocx, freex);int *p = sample_module_create_int_array(2);

      基于Interface的注入

      面向?qū)ο缶幊逃幸粋€(gè)接口(Interface)的概念。從概念上講,接口是一個(gè)抽象類,代表一系列行為相同的類;從實(shí)現(xiàn)上來(lái)講,接口就是一堆方法的集合。C語(yǔ)言雖然沒(méi)有接口的的概念,但是完全可以實(shí)現(xiàn)接口的功能,通過(guò)結(jié)構(gòu)體將一系列函數(shù)指針組合起來(lái),就可以實(shí)現(xiàn)接口的功能。比如我們需要實(shí)現(xiàn)一個(gè)緩存功能模塊,包括set_value和get_value兩個(gè)方法,為了使模塊更具有擴(kuò)展性,我們先定義抽象接口

      struct cache_interface{ ///store kv in cache int (*set_value)(void *instance, const char *key, const char *value); ///find kv in cache int (*get_value)(void *instance, const char *key, char **value_out);};

      在面向?qū)ο笳Z(yǔ)言中,接口不能實(shí)例化。C語(yǔ)言中雖然這個(gè)結(jié)構(gòu)體可以實(shí)例化,但是實(shí)例化后沒(méi)有任何意義,其中的函數(shù)指針仍然無(wú)值可賦,所以我們要在另外的文件中實(shí)現(xiàn)這個(gè)接口:

      ///實(shí)現(xiàn)方式---本地文件緩存struct cache_local_file{ ///必須是第一個(gè)成員 struct cache_interface methods; char file_path[32]; FILE *fp;};int set_value(struct cache_interface *instance, const char *key, const char *value){ struct cache_local_file *ins = (struct cache_local_file *)instance; fprintf(ins->fp, '%s:%s', key, value); return 0;}int get_value(struct cache_interface *instance, const char *key, const char **value_out){ *value_out = 'sample data'; return 0;}//創(chuàng)建實(shí)例(創(chuàng)建一個(gè)實(shí)例,相當(dāng)于構(gòu)造函數(shù))int cahce_local_file_create(const char *path, struct cache_interface **instance){ struct cache_local_file *ins = (struct cache_local_file *)malloc(sizeof(cache_local_file)); strncpy(ins->file_path, sizeof(ins->file_path), path); ins->fp = fopen(path); ins->methods.get_value = get_value; ins->methods.set_value = set_value; *instance = &(ins->methods); return 0;}

      上面實(shí)現(xiàn)一個(gè)利用本地文件存儲(chǔ)數(shù)據(jù)的緩存方法,為了更變的使用這些實(shí)現(xiàn),我們需要提供統(tǒng)一的API來(lái)共用戶使用,這樣當(dāng)緩存的具體實(shí)現(xiàn)有變化時(shí),使用緩存的用戶不用大規(guī)模修改代碼,甚至不用修改代碼。下面我們類似于面向?qū)ο罄锏?em>工廠模式來(lái)提供這些API。

      struct cache_implement{ char name[32], int (*create)(const char *input, struct cache_interface **instance);}struct cache_implement impl[32] = {0};void init(){ strncpy(impl[0].name, sizeof(impl[0].name), 'local_file'); impl[0].create = cahce_local_file_create;  ///more implement to add};int cache_create(const char *type, const char *param, struct cache_interface **ins){ for(int i =0 ; i < 32; i++) { if (0 == strcmp(type, impl[i].name)) { impl[i].create(type, param, ins); } }  return 0;}int cache_set_value(struct cache_interface *ins, const char *key, const char *value){ ///another user code   ///set kv return ins->set_value(ins, key, value);}int cache_get_value(struct cache_interface *ins, const char *key, const cahr **value_out){ ///another user code;  ///get kv return ins->get_value(ins, key, value);}

      這樣的話,使用者就只關(guān)注到三個(gè)API,如果要變換不同的緩存實(shí)現(xiàn)(比如使用redis或者memcache存儲(chǔ)數(shù)據(jù)),只要修改cache_create的type參數(shù)即可。

      總結(jié):

      • 參數(shù)注入:適合簡(jiǎn)單函數(shù)的場(chǎng)景,一般如果單個(gè)函數(shù)(不屬于任何模塊的工具式函數(shù))如果需要調(diào)用外部的API,可以試著用注入的方法。
      • 設(shè)置接口注入:適合運(yùn)行時(shí)設(shè)置一個(gè)模塊調(diào)用的外部API。
      • interface注入:適合將一個(gè)模塊的一組API一起設(shè)置到摸個(gè)調(diào)用這個(gè),是對(duì)一個(gè)模塊的API的整個(gè)注入。

        本站是提供個(gè)人知識(shí)管理的網(wǎng)絡(luò)存儲(chǔ)空間,所有內(nèi)容均由用戶發(fā)布,不代表本站觀點(diǎn)。請(qǐng)注意甄別內(nèi)容中的聯(lián)系方式、誘導(dǎo)購(gòu)買等信息,謹(jǐn)防詐騙。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請(qǐng)點(diǎn)擊一鍵舉報(bào)。
        轉(zhuǎn)藏 分享 獻(xiàn)花(0

        0條評(píng)論

        發(fā)表

        請(qǐng)遵守用戶 評(píng)論公約

        類似文章 更多