博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
Object-base编程
阅读量:6583 次
发布时间:2019-06-24

本文共 3065 字,大约阅读时间需要 10 分钟。

hot3.png

在C++中,一般的架构设计都是基于多态,基于接口编程。一般的是基类提供接口,子类根据具体的业务逻辑来实现接口,以此来提供程序设计的过程中的可注入性,提高灵活性,但是事实可能不经如此。引入了多态,其实也就是引入了耦合,其强制规定了继承基类和接口的形式,这在整体继承体系中都是不可以更改的。

如下例子:

#ifndef ANIMAL_H#define ANIMAL_H#include 
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 
#include
#include
class Work{public: typedef std::function
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
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
_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
为什么,我是想在提供一些变化。
比如,
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,¶));logic.make();worker.aMessageComing();para.para2 += 10;worker.aMessageComing();logic.printMessages();
运行结果:
 
这样可以不改变Work,多引入一个参数,可是却也映入了一个全局的变量,在需要的使用需要改变参数,因为可能我们不知道函数的调用时间,我们需要做随时改变。
 
这样我们就不需要通过继承完成注入,使用function和bind需要通过对象来完成注入。
不使用继承虚函数使用函数对象可以获得运行时的效率,函数对象可以被inline,提供了性能优化。
 
 
 
 
 

转载于:https://my.oschina.net/u/854744/blog/418219

你可能感兴趣的文章
MySQL主从多种架构部署及常见错误问题解析
查看>>
关于负载均衡的几个知识点
查看>>
使用xtrabackup备份innodb引擎的数据库
查看>>
jQuery EasyUI DataGrid动态合并单元格解决方案
查看>>
V 2 heartbeat V2(HA)
查看>>
程序员回家过年生存指南
查看>>
Vim应用
查看>>
esxi安装
查看>>
14、系统架构师指南 - 软件项目角色指南系列文章
查看>>
微软职位内部推荐-SW Engineer II for Windows System
查看>>
【技术交流】让我们来谈一谈多线程和并发任务
查看>>
功能对外vsftpd 服务搭建过程
查看>>
Linux下有7种运行级别
查看>>
Redis分布式锁
查看>>
/etc/fstab文件说明
查看>>
zabbix应用之Low-level discovery监控磁盘IO
查看>>
ROW ARCHIVE
查看>>
Tech-ED2006会场见闻图片集
查看>>
python 自定义异常类学习
查看>>
centos线上分区partprobe命令
查看>>