C++接口與多種實(shí)現(xiàn)的隔離

C++接口與多種實(shí)現(xiàn)的隔離

本文介紹一種將接口和實(shí)現(xiàn)完全隔離的技術(shù), 其特點(diǎn)是增加新的實(shí)現(xiàn)不影響任何已有代碼, 只需在新源文件中實(shí)現(xiàn)新的接口.
該方法見(jiàn)于SICP(計(jì)算機(jī)程序的構(gòu)造和解釋).

具體方法就是通過(guò)Install(Id, Maker)Make(Id)來(lái)添加和使用新的實(shí)現(xiàn). 實(shí)現(xiàn)通過(guò)Id來(lái)唯一標(biāo)識(shí), Install(Id, Maker)供新實(shí)現(xiàn)的作者調(diào)用以完成安裝或注冊(cè). 使用者通過(guò)Make(Id)來(lái)使用(構(gòu)造)它. Id的值應(yīng)該是使用者能獲取的, 比如事先已知或讀取配置文件等等.

下面示例中, LoggerWrite()接口只是輸出一個(gè)字符串, 具體實(shí)現(xiàn)(派生類)使用字符串作為Id:

// file0: logger.h
// ...
class Logger
{ 
public:
    typedef std::string Id;
    typedef std::shared_ptr<Logger> Ptr;
    static Ptr Make(const Id &id) {
        auto pos = Makers().find(id);
        if (pos == Makers().end()) {
            return Ptr();
        } else {
            return pos->second();
        }
    }

    int Write(const std::string &msg) { return DoWrite(msg); }
private:
    virtual int DoWrite(const std::string &msg) = 0;
protected:
    typedef std::function<Ptr()> Maker;
    static bool Install(const Id &id, const Maker &func) {
        if (Makers().find(id) != Makers().end()) {
            return false;
        } else {
            Makers()[id] = func;
            return true;
        }
    }
    static std::map<Id, Maker> & Makers() {
        static std::map<Id, Maker> s;
        return s;
    }
};
// ...

ConsoleLogger是一個(gè)實(shí)現(xiàn), 其Id我們?cè)O(shè)置為"console".

// file1: console_logger.cpp
// ....
#include "logger.h"
class ConsoleLogger : public Logger
{
public:
    static bool InstallThis() {
        auto maker = []() { return Logger::Ptr(new ConsoleLogger); };
        return Logger::Install("console", maker);
    }
private:
    int DoWrite(const std::string &msg) override {
        std::cout << msg << std::endl;
        return msg.size();
    }
};
namespace {
const bool kInstalled = ConsoleLogger::InstallThis();
}

使用示例如下:

//...
#include "logger.h"

int main(int argc, const char *argv[])
{
    Logger::Ptr lgr = Logger::Make("console");
    assert(lgr);
    lgr->Write("Hello, World!");
    return 0;
}

注意到了吧, 添加新實(shí)現(xiàn)的時(shí)候, 接口和其他實(shí)現(xiàn)不需要修改任何代碼, 使用時(shí)只需要Id值, 甚至不需要知道ConsoleLogger等實(shí)現(xiàn)(類)的存在, 也不必提供頭文件.

這種方法依賴統(tǒng)一的Make接口, 示例中的Make沒(méi)有參數(shù), 實(shí)際項(xiàng)目中可能會(huì)有不同, 比如FileLogger可能需要一個(gè)文件路徑. 遇到差異可能就要void*之類的參數(shù)來(lái)處理了. 當(dāng)然你也可以重載多個(gè)Make, 不過(guò)那就比較繁瑣了.

其實(shí), 這種Install,Make方法是通用的, 可以提取出來(lái)作為模板類重復(fù)使用. 但要注意處理Make接口問(wèn)題, 需要用variable template支持多種接口, 還要注意各個(gè)接口類的Makers()不要混淆.

2017-06-08

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末蚊惯,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌老充,老刑警劉巖,帶你破解...
    沈念sama閱讀 222,000評(píng)論 6 515
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡憨栽,警方通過(guò)查閱死者的電腦和手機(jī)翼虫,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,745評(píng)論 3 399
  • 文/潘曉璐 我一進(jìn)店門掸宛,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人招拙,你說(shuō)我怎么就攤上這事唧瘾。” “怎么了别凤?”我有些...
    開(kāi)封第一講書人閱讀 168,561評(píng)論 0 360
  • 文/不壞的土叔 我叫張陵饰序,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我规哪,道長(zhǎng)求豫,這世上最難降的妖魔是什么? 我笑而不...
    開(kāi)封第一講書人閱讀 59,782評(píng)論 1 298
  • 正文 為了忘掉前任,我火速辦了婚禮杯巨,結(jié)果婚禮上是晨,老公的妹妹穿的比我還像新娘。我一直安慰自己舔箭,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 68,798評(píng)論 6 397
  • 文/花漫 我一把揭開(kāi)白布。 她就那樣靜靜地躺著镜会,像睡著了一般檬寂。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上戳表,一...
    開(kāi)封第一講書人閱讀 52,394評(píng)論 1 310
  • 那天桶至,我揣著相機(jī)與錄音,去河邊找鬼匾旭。 笑死镣屹,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的价涝。 我是一名探鬼主播女蜈,決...
    沈念sama閱讀 40,952評(píng)論 3 421
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼色瘩!你這毒婦竟也來(lái)了伪窖?” 一聲冷哼從身側(cè)響起,我...
    開(kāi)封第一講書人閱讀 39,852評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤居兆,失蹤者是張志新(化名)和其女友劉穎覆山,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體泥栖,經(jīng)...
    沈念sama閱讀 46,409評(píng)論 1 318
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡簇宽,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,483評(píng)論 3 341
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了聊倔。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片晦毙。...
    茶點(diǎn)故事閱讀 40,615評(píng)論 1 352
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖耙蔑,靈堂內(nèi)的尸體忽然破棺而出见妒,到底是詐尸還是另有隱情,我是刑警寧澤甸陌,帶...
    沈念sama閱讀 36,303評(píng)論 5 350
  • 正文 年R本政府宣布须揣,位于F島的核電站,受9級(jí)特大地震影響钱豁,放射性物質(zhì)發(fā)生泄漏耻卡。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,979評(píng)論 3 334
  • 文/蒙蒙 一牲尺、第九天 我趴在偏房一處隱蔽的房頂上張望卵酪。 院中可真熱鬧幌蚊,春花似錦、人聲如沸溃卡。這莊子的主人今日做“春日...
    開(kāi)封第一講書人閱讀 32,470評(píng)論 0 24
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)瘸羡。三九已至漩仙,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間犹赖,已是汗流浹背队他。 一陣腳步聲響...
    開(kāi)封第一講書人閱讀 33,571評(píng)論 1 272
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留峻村,地道東北人麸折。 一個(gè)月前我還...
    沈念sama閱讀 49,041評(píng)論 3 377
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像雀哨,于是被迫代替她去往敵國(guó)和親磕谅。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,630評(píng)論 2 359

推薦閱讀更多精彩內(nèi)容

  • Spring Cloud為開(kāi)發(fā)人員提供了快速構(gòu)建分布式系統(tǒng)中一些常見(jiàn)模式的工具(例如配置管理雾棺,服務(wù)發(fā)現(xiàn)膊夹,斷路器,智...
    卡卡羅2017閱讀 134,704評(píng)論 18 139
  • Android 自定義View的各種姿勢(shì)1 Activity的顯示之ViewRootImpl詳解 Activity...
    passiontim閱讀 172,302評(píng)論 25 707
  • Spring Boot 參考指南 介紹 轉(zhuǎn)載自:https://www.gitbook.com/book/qbgb...
    毛宇鵬閱讀 46,859評(píng)論 6 342
  • 我必須保持樂(lè)觀捌浩,這樣無(wú)論明天天晴或者下雨放刨,我才有奮斗下去的勇氣。
    人言白一閱讀 191評(píng)論 0 0
  • 【作業(yè)】 作業(yè)要求的是約談一位朋友或者親人尸饺,我平時(shí)社交活動(dòng)不多进统,之前運(yùn)用書中的方法跟一個(gè)朋友聊天,談話完畢以后向他...
    神勇小輝閱讀 202評(píng)論 0 0