Object-base編程

在C++中,通常的架構設計都是基於多態,基於接口編程。通常的是基類提供接口,子類根據具體的業務邏輯來實現接口,以此來提供程序設計的過程當中的可注入性,提升靈活性,可是事實可能不經如此。引入了多態,其實也就是引入了耦合,其強制規定了繼承基類和接口的形式,這在總體繼承體系中都是不能夠更改的。ios

以下例子:編程

#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,提供了性能優化。
相關文章
相關標籤/搜索