程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> C語言 >> C++ >> C++入門知識 >> 應該用bind+function取代虛函數嗎?,bindfunction

應該用bind+function取代虛函數嗎?,bindfunction

編輯:C++入門知識

應該用bind+function取代虛函數嗎?,bindfunction


用bind+function取代虛函數在好幾年前就有人提出了,曾引起廣泛的討論,有支持的有反對的,可能贊成的人占大多數。這個話題挺有趣,本來是作為技術沙龍的開放性話題來討論的,由於時間關系並沒有討論。今天就來具體探討一下這個問題,我將做兩個實驗來驗證一下這兩種做法,具體是實現兩個模式:策略模式和責任鏈模式。我將分別用經典的虛函數和bind+function來實現這兩個模式。通過這兩個實驗來得出我的結論。

實驗一:策略模式的實現

1.虛函數方式實現策略模式

class Calculater { public: virtual int calculate(int x, int y) = 0; }; class Minus : public Calculater { public: int calculate(int x, int y) { return x - y; } }; class Plus : public Calculater { public: int calculate(int x, int y) { return x + y; } }; class CalcuClient { private: Calculater* m_caculater; public: CalcuClient(Calculater* caculater) : m_caculater(caculater){} int calculate(int x, int y) { return m_caculater->calculate(x, y); } }; View Code

2.bind+function方式實現策略模式

class NewCalcuClient
{
private:
    std::function<int(int, int)> m_function;

public:
    NewCalcuClient(std::function<int(int, int)> function) : m_function(function){}

    int calculate(int x, int y)
    {
        return m_function(x, y);
    }
};

測試代碼:

    Minus minus;
    CalcuClient client(&minus);

    Plus plus;
    CalcuClient client2(&plus);

    int r = client.calculate(7, 4);
    int r2 = client2.calculate(7, 4);

   //bind+function NewCalcuClient newclient(boost::bind(&Minus::calculate, &minus, _1, _2)); NewCalcuClient newclient2(boost::bind(&Plus::calculate, &plus, _1, _2)); int r3 = newclient.calculate(7, 4); int r4 = newclient2.calculate(7, 4);

  bind+function取代虛函數的一個重要理由是虛函數帶來了效率損失,bind+function效率更高,我做了一個性能測試, 分別調用10000000次來看耗時,發現虛函數比bind+function方式要快一些,無論是用標准庫的bind還是boost的bind,都比虛函數方式要慢,所以說bind+function比虛函數性能更好是想當然,站不住腳的。接下來看第二個實驗。

實驗二:責任鏈模式的實現

1.虛函數方式實現責任鏈模式

struct Request
{
    int RequestType;
};

class Handler
{
protected:
    std::shared_ptr<Handler> m_next;
public:
    Handler(std::shared_ptr<Handler> next) : m_next(next){}

    virtual void HandleRequest(Request) = 0;
};

class ConcreteHandler1 : public Handler
{
public:
    ConcreteHandler1(std::shared_ptr<Handler> next) : Handler(next){}

    void HandleRequest(Request request)
    {
        if (request.RequestType == 1)
        {
            cout << "request handled in ConcreteHandler1" << endl;
        }
        else
        {
            if (m_next != nullptr)
                m_next->HandleRequest(request);
        }
    }
};

class ConcreteHandler2 : public Handler
{
public:
    ConcreteHandler2(std::shared_ptr<Handler> next) : Handler(next){}

    void HandleRequest(Request request)
    {
        if (request.RequestType == 2)
        {
            cout << "request handled in ConcreteHandler2" << endl;
        }
        else
        {
            if (m_next != nullptr)
                m_next->HandleRequest(request);
        }
    }
};

class ConcreteHandler3 : public Handler
{
public:
    ConcreteHandler3(std::shared_ptr<Handler> next) : Handler(next){}

    void HandleRequest(Request request)
    {
        if (request.RequestType == 3)
        {
            cout << "request handled in ConcreteHandler3" << endl;
        }
        else
        {
            if (m_next != nullptr)
                m_next->HandleRequest(request);
        }
    }
};

2.bind+function方式實現責任鏈模式

class ChainHandler
{
    
public:
    std::function<void(Request)> function;

    void HandleRequest(Request request)
    {
        function(request);
    }

    std::function<void(Request)>& getfunction()
    {
        return function;
    }
};

void assemble(std::function<void(Request)> call, std::function<void(Request)> next, Request request)
{
    if (next != nullptr)
        next(request);
    else
        call(request);
}

測試代碼:

void Test()
{
    auto thirdHandler = std::make_shared<ConcreteHandler3>(nullptr); 
    auto secondHandler = std::make_shared<ConcreteHandler2>(thirdHandler); 
    auto firstHandler = std::make_shared<ConcreteHandler1>(secondHandler); 

    Request request = { 2 };
    firstHandler->HandleRequest(request);

    ChainHandler chain;
    
    std::function<void(Request)> f1 = std::bind(&ConcreteHandler1::HandleRequest, firstHandler, std::placeholders::_1);
    std::function<void(Request)> f2 = std::bind(&ConcreteHandler2::HandleRequest, secondHandler, std::placeholders::_1);
    std::function<void(Request)> f3 = std::bind(&ConcreteHandler3::HandleRequest, thirdHandler, std::placeholders::_1);
    
    chain.function = std::bind(&assemble, f1, chain.function, std::placeholders::_1);
    chain.function = std::bind(&assemble, f2, chain.function, std::placeholders::_1);
    chain.function = std::bind(&assemble, f3, chain.function, std::placeholders::_1);

    chain.HandleRequest(request);
}

bind+function實現責任鏈模式的關鍵代碼在這裡:

chain.function = std::bind(&assemble, f1, chain.function, std::placeholders::_1);
chain.function = std::bind(&assemble, f2, chain.function, std::placeholders::_1);
chain.function = std::bind(&assemble, f3, chain.function, std::placeholders::_1);

chain.HandleRequest(request);

  這幾行代碼通過merge不斷地往function鏈條中加function,最後調用的時候會從鏈條的第一個function開始調用。

  bind+function取代虛函數的另外一個理由是松耦合,去除了繼承的限制,方法的實現更加靈活,確實,低耦合確實是bind+function最大的優點,然而這個最大的優點也成了它最大的缺點,當需要替代的虛函數增多時,組裝function的復雜度也在增加,太松散了導致代碼也不夠直觀,代碼的內聚性也變低了。比如上面責任鏈模式的實現,虛函數的實現明顯比bind+function的實現要優雅。

結論

  bind+function相比虛函數的實現在性能上並不占優,最大的優點是大大降低類之間的耦合度,缺點是太過於松散導致代碼的內聚性和可讀性降低。

  bind+function適用的場景:

  1.迫切需要接口和實現解耦;

  2.需要解耦的接口很少。

  滿足這兩種情況適合用bind+function,否則還是用虛函數更好。

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved