C 框架設計 2 更優雅的建立物件

2021-10-06 07:48:17 字數 3079 閱讀 3322

上一章中我們是用以下**來進行物件建立的。這段**並沒有什麼問題,每次新增乙個層的時候在此處新增els if即可。不過還是可以有更優雅一些的實現。

layerbase *

laye***ctory

(string classname)

計畫構造一張map對映表,key為類名或者id,value為可返回物件的函式指標。這樣上面的函式就可以變成這乙個樣子。

// laye***ctory.h

#include

using std::function;

class

laye***ctory

static

void

registercreater

(string classname, function> creater)

private

:static map>> s_createmap;};

// laye***ctory.cpp

#include

"laye***ctory.h"

layerbase *

laye***ctorymap

(string classname)

s_createmap就是這個對映表,最直接的想法是把每個類的建構函式賦予s_createmap,可是c++是無法獲取指向類的建構函式的函式指標

所以轉變思路,用另乙個函式(比如叫fwrap)把建構函式封起來,然後再把fwrap的位址賦予map表即可。如果在每個layer類裡面定義這樣的fwrap函式。雖然成員函式可以獲得函式指標,但其在呼叫的時必須要有具體物件(因為引數列表中需要傳this指標),這樣呼叫就顯得麻煩了。所以最後就只有全域性函式或者類的靜態函式符合要求。

以conv層舉例,得到以下實現:

class

auto_factory_conv

;static layerbase*

createlayer()

};

可以看到這裡把註冊語句放到了auto_factory_conv 類的建構函式中。這是為了只要宣告乙個物件即可自動去註冊乙個字串和物件構建器的對映關係。

比如:

static auto_factory_conv g_obj_for_register_conv;
createlayer函式就是上面所描述的fwrap了。

可以發現這段**非常模式化,按照c++慣例用巨集來總結下。

#define register_layer_create(idname,classname) \

class auto_factory_##idname \

; \ static layerbase* createlayer() \

}; \

static auto_factory_##idname class_creater_register_##idname;

最終完整**如下:

// laye***ctory.h

#include

using std::function;

layerbase *

laye***ctory

(string classname)

;class

laye***ctory

static

void

registercreater

(string classname, function> creater)

private

:static map>> s_createmap;};

#define register_layer_create(idname,classname) \

class auto_factory_##idname \

; \ static layerbase* createlayer() \

}; \

static auto_factory_##idname class_creater_register_##idname;

// laye***ctory.cpp

#include

"laye***ctory.h"

map>> laye***ctory::s_createmap;

// register

register_layer_create

(conv,layerconv)

register_layer_create

(pooling, layerpooling)

register_layer_create

(softmax, layersoftmax)

layerbase *

laye***ctorymap

(string classname)

饒了一圈,**量似乎沒有減小,之前的if else不挺好的嗎。考慮到更複雜的需求時才能體現他的好處,比如我們有自動生成**的需求(根據配置檔案,批量生成重複**)。那麼插一句巨集會比修改函式體內的邏輯來的更方便。

register_layer_create巨集最終應用在laye***ctory.cpp中。即用於註冊的類宣告只有這個cpp檔案可見,且定義的幫助註冊的類也是置為static的,這些都是為了把物件構建器的細節封裝到這個編譯單元內。

根據工廠模式的定義,屬於簡單工廠(甚至不屬於設計模式,就是應用了封裝的思想)。所以設計模式不是用的越多越複雜越好,適合業務的才是最好的。

注意s_createmap不能設定成全域性變數,因為在不同的編譯單元內,全域性變數的初始化順序是未定義的。比如在某個.cpp中向全域性的s_createmap進行設定,但是s_createmap此時不能保證已經被初始化完成了。乙個更大的原則是不要定義全域性的class物件,如果確實需要則應該把其封裝到乙個類中。

1.工廠模式

2.各類c++框架的「註冊」機制基本都是此類實現

框架設計的粒度

先拿乙個常見的oa中的許可權管理舉例,常規的設計方式無非就是許可權 角色 人這三層,關係如下 那麼這樣的許可權設計是可以基本滿足乙個oa的需要的,那麼只需要做乙個filter去進行許可權的控制就ok了。如果考慮到軟體的擴充套件性貌似也足夠用了。但是考慮一下顯示情況,如果上線之後許可權需要增加意味著什...

現用框架設計的基本設計

基本設計 框架是為了解決 出現大量的冗餘,和提高開發人員的開發效率,而這些框架的基本設計,都是將一些變化的資料的值存放到乙個檔案中,而這個檔案必須要是乙個關係對映檔案,而已是可以符合複雜的硬關係和軟關係對映的,因為在專案中可能會出現大量問題,而要應對這些問題則需要提供相應的路徑來解決。而這個檔案的最...

反射 框架設計的靈魂

獲取class物件的方式 1.class.forname 全類名 將位元組碼檔案載入進記憶體,返回class物件 多用於配置檔案,將類名定義在配置檔案中。讀取檔案,載入類 2.類名.class 通過類名的屬性class獲取 多用於引數的傳遞 3.物件.getclass getclass 方法在obj...