基本用途编程
boost::function就像C#里的delegate,能够指向任何函数,包括成员函数。当用bind把某个成员函数绑到某个对象上时,咱们获得了一个closure(闭包)。例如:设计模式
class Foo { public: void methodA(); void methodInt(int a); }; class Bar { public: void methodB(); }; boost::function<void()> f1; // 无参数,无返回值 Foo foo; f1 = boost::bind(&Foo::methodA, &foo); f1(); // 调用 foo.methodA(); Bar bar; f1 = boost::bind(&Bar::methodB, &bar); f1(); // 调用 bar.methodB(); f1 = boost::bind(&Foo::methodInt, &foo, 42); f1(); // 调用 foo.methodInt(42); boost::function<void(int)> f2; // int 参数,无返回值 f2 = boost::bind(&Foo::methodInt, &foo, _1); f2(53); // 调用 foo.methodInt(53);
若是没有boost::bind,那么boost::function就什么都不是,而有了bind(),“同一个类的不一样对象能够delegate给不一样的实现,从而实现不一样的行为”(myan语),简直就无敌了。闭包
对程序库的影响编程语言
程序库的设计不该该给使用者带来没必要要的限制(耦合),而继承是仅次于最强的一种耦合(最强耦合的是友元)。若是一个程序库限制其使用者必须从某个class派生,那么我以为这是一个糟糕的设计。不巧的是,目前有些程序库就是这么作的。函数
例1:线程库工具
常规OO设计: 线程
写一个Thread base class,含有(纯)虚函数 Thread#run(),而后应用程序派生一个继承class,覆写run()。程序里的每一种线程对应一个Thread的派生类。例如Java的Thread能够这么用。设计
缺点:若是一个class的三个method须要在三个不一样的线程中执行,就得写helper class(es)并玩一些OO把戏。code
基于closure的设计: 面向对象设计模式
令Thread是一个具体类,其构造函数接受Callable对象。应用程序只需提供一个Callable对象,建立一份Thread实体,调用Thread#start()便可。Java的Thread也能够这么用,传入一个Runnable对象。C#的Thread只支持这一种用法,构造函数的参数是delegate ThreadStart。boost::thread也只支持这种用法。
// 一个基于 closure 的 Thread class 基本结构 class Thread { public: typedef boost::function<void()> ThreadCallback; Thread(ThreadCallback cb) : cb_(cb) { } void start() { /* some magic to call run() in new created thread */ } private: void run() { cb_(); } ThreadCallback cb_; // ... }; 使用: class Foo { public: void runInThread(); }; Foo foo; Thread thread(boost::bind(&Foo::runInThread, &foo)); thread.start();
对面向对象程序设计的影响
一直以来,我对面向对象有一种厌恶感,叠床架屋,绕来绕去的,一拳拳打在棉花上,不解决实际问题。面向对象三要素是封装、继承和多态。我认为封装是根本的,继承和多态则是无关紧要。用class来表示concept,这是根本的;至于继承和多态,其耦合性太强,每每不划算。
继承和多态不只规定了函数的名称、参数、返回类型,还规定了类的继承关系。在现代的OO编程语言里,借助反射和attribute/annotation,已经大大放宽了限制。举例来讲,JUnit 3.x 是用反射,找出派生类里的名字符合 void test*() 的函数来执行,这里就没继承什么事,只是对函数的名称有部分限制(继承是全面限制,一字不差)。至于JUnit 4.x 和 NUnit 2.x 则更进一步,以annoatation/attribute来标明test case,更没继承什么事了。
个人猜想是,当初提出面向对象的时候,closure尚未一个通用的实现,因此它没能算做基本的抽象工具之一。如今既然closure已经这么方便了,或许咱们应该从新审视面向对象设计,至少不要那么滥用继承。
自从找到了boost::function+boost::bind这对神兵利器,不用再考虑类直接的继承关系,只须要基于对象的设计(object-based),拳拳到肉,程序写起来顿时顺手了不少。
对面向对象设计模式的影响
既然虚函数能用closure代替,那么不少OO设计模式,尤为是行为模式,失去了存在的必要。另外,既然没有继承体系,那么建立型模式彷佛也没啥用了。
最明显的是Strategy,不用累赘的Strategy基类和ConcreteStrategyA、ConcreteStrategyB等派生类,一个boost::function<>成员就解决问题。在《设计模式》这本书提到了23个模式,我认为iterator有用(或许再加个State),其余都在摆谱,拉虚架子,没啥用。或许它们解决了面向对象中的常见问题,不过要是个人程序里连面向对象(指继承和多态)都不用,那彷佛也不用叨扰面向对象设计模式了。
或许closure-based programming将做为一种新的programming paradiam而流行起来。