Object-base編程

來源:互聯網
上載者:User

標籤:style   blog   http   color   使用   os   資料   io   

在C++中,一般的架構設計都是基於多態,基於介面編程。一般的是基類提供介面,子類根據具體的商務邏輯來實現介面,以此來提供者設計的過程中的可注入性,提高靈活性,但是事實可能不經如此。引入了多態,其實也就是引入了耦合,其強制規定了繼承基類和介面的形式,這在整體繼承體系中都是不可以更改的。

如下例子:

#ifndef ANIMAL_H#define ANIMAL_H#include <iostream>class Animal{public:virtual void eat() = 0;virtual ~Animal() = 0;};Animal::~Animal(){}class Dog : public Animal{public:void eat(){std::cout << "DOG EAT MEAT!\n";}~Dog() {}};class Cat : public Animal{public:void eat(){std::cout << "CAT EAT FISH!\n";}~Cat() {}};class Pet{public:Pet(Animal *_a) : _aAnimal(_a){}
        ~Pet()
        {
            delete _aAnimal;
        }void eat() {_aAnimal->eat();}private:Animal *_aAnimal;};#endif // ANIMAL_H

在main函數中

Dog *dog = new Dog();Pet p(dog);p.eat();Cat *cat = new Cat();Pet p1(cat);p1.eat();

我們通過多態實現了注入,這就和具體類型和函數形式相關,可是如果現在,我們的eat還是多了個參數Foot,那麼我們只有改源碼,可以改動eat函數原型,或則在添加一個eat函數,這就是多態引入的耦合。


C++0x中的bind函數和function模板類為我們提供了很好的設計解決方案,提供多態基於函數對象,其只和函數的返回值和參數有關。陳碩老師稱其為Object-base編程,通過對象來完成功能注入。拳拳到肉(陳老師原話)。關於bind和function不清楚的可以先瞭解下,這邊就不贅述了。

看這個例子:

#include <iostream>#include <functional>#include <list>class Work{public:typedef std::function<void ()> doAmessage;void registerDoMessage(const doAmessage &f){_aAmessage = f;}void do_aTask(){std::cout << "DO A TASK!\n";}void aMessageComing(){_aAmessage();}private:doAmessage _aAmessage;};class Logic{public:typedef std::function<void ()> doTaskCallBack;Logic(const doTaskCallBack &f) : _dtask(f){}void make(){_dtask();}void aMessageComing(){_messageList.push_back("A TASK!");}void printMessages(){for (auto ite = _messageList.begin(); ite != _messageList.end(); ++ite){std::cout << (*ite).data() << '\n';}}private:doTaskCallBack _dtask;std::list<std::string> _messageList;};int main(){//std::cout << "Hello World\n";Work worker;Logic logic(std::bind(&Work::do_aTask,worker));worker.registerDoMessage(std::bind(&Logic::aMessageComing,&logic));logic.make();worker.aMessageComing();worker.aMessageComing();logic.printMessages();return 0;}

work是一個底層的操作類,Logic是一個與業務相關的類,work為Logic提供一些底層服務,logic知道work對底層資料的操作。
Work::do_aTask為Logic提供服務,在Logic::make中調用,在
Logic logic(std::bind(&Work::do_aTask,worker));這句完成了注入操作。
Work::aMessageComing,需要Logic提供的具體的邏輯,在
worker.registerDoMessage(std::bind(&Logic::aMessageComing,&logic));
完成了注入。

如果現在我定義了一個class,其只用提供一個void xxx()成員函數,那就可以直接綁定給Work使用。

可以注意到我的回調對象都是

std::function<void ()>
為什麼,我是想在提供一些變化。
比如,
Logic的
aMessageComing(Parameter *_p)
函數添加了一個函數,我希望Work不需要改變,這就需要一個參數,使用對象來實現對參數的儲存。
定義如下:
struct Parameter{Parameter() : para1(0),para2(0){ }int para1;int para2;};
使用如下:
Parameter para;Work worker;Logic logic(std::bind(&Work::do_aTask,worker));worker.registerDoMessage(std::bind(&Logic::aMessageComing,&logic,&para));logic.make();worker.aMessageComing();para.para2 += 10;worker.aMessageComing();logic.printMessages();
運行結果:
這樣可以不改變Work,多引入一個參數,可是卻也映入了一個全域的變數,在需要的使用需要改變參數,因為可能我們不知道函數的調用時間,我們需要做隨時改變。
這樣我們就不需要通過繼承完成注入,使用function和bind需要通過對象來完成注入。
不使用繼承虛函數使用函數對象可以獲得運行時的效率,函數對象可以被inline,提供了效能最佳化。



聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.