引言
在查看OCCT项目源码的时候看到这种C++链式编程方法,查看维基百科正好有例子,于是作此记录。
见解
这种方法通过返回this 或者 self当前指针对象,使得代码以方法链的形式一直书写下去
形如:
const bool okImport =read().mode().transfer().dosomething().execute();
在C++中有个专业术语叫fluent interface ,属于API设计模式中的一种,这种方法其实在JavaScript中大量使用。实验表明,虽然多多少少给阅读代码带来不便性,使用起来倒是挺丝滑的。
历史:
术语 “fluent interface” 是在2005年末创造的,尽管这种接口的整体风格可以追溯到20世纪70年代Smalltalk中方法级联的发明,以及20世纪80年代的大量例子。 一个常见的例子是c++中的iostream库,它使用<<或>>操作符进行消息传递,向同一个对象发送多个数据,并允许对其他方法调用使用“操纵符”。 其他早期的例子包括Garnet系统(在Lisp中始于1988年)和Amulet系统(在c++中始于1994年),它们使用这种风格来创建对象和赋值属性。
例子:
===C++===
// Basic definition
class GlutApp {
private:
int w_, h_, x_, y_, argc_, display_mode_;
char **argv_;
char *title_;
public:
GlutApp(int argc, char** argv) {
argc_ = argc;
argv_ = argv;
}
void setDisplayMode(int mode) {
display_mode_ = mode;
}
int getDisplayMode() {
return display_mode_;
}
void setWindowSize(int w, int h) {
w_ = w;
h_ = h;
}
void setWindowPosition(int x, int y) {
x_ = x;
y_ = y;
}
void setTitle(const char *title) {
title_ = title;
}
void create(){;}
};
// Basic usage
int main(int argc, char **argv) {
GlutApp app(argc, argv);
app.setDisplayMode(GLUT_DOUBLE|GLUT_RGBA|GLUT_ALPHA|GLUT_DEPTH); // Set framebuffer params
app.setWindowSize(500, 500); // Set window params
app.setWindowPosition(200, 200);
app.setTitle("My OpenGL/GLUT App");
app.create();
}
// Fluent wrapper
class FluentGlutApp : private GlutApp {
public:
FluentGlutApp(int argc, char **argv) : GlutApp(argc, argv) {} // Inherit parent constructor
FluentGlutApp &withDoubleBuffer() {
setDisplayMode(getDisplayMode() | GLUT_DOUBLE);
return *this;
}
FluentGlutApp &withRGBA() {
setDisplayMode(getDisplayMode() | GLUT_RGBA);
return *this;
}
FluentGlutApp &withAlpha() {
setDisplayMode(getDisplayMode() | GLUT_ALPHA);
return *this;
}
FluentGlutApp &withDepth() {
setDisplayMode(getDisplayMode() | GLUT_DEPTH);
return *this;
}
FluentGlutApp &across(int w, int h) {
setWindowSize(w, h);
return *this;
}
FluentGlutApp &at(int x, int y) {
setWindowPosition(x, y);
return *this;
}
FluentGlutApp &named(const char *title) {
setTitle(title);
return *this;
}
// It doesn't make sense to chain after create(), so don't return *this
void create() {
GlutApp::create();
}
};
// Fluent usage
int main(int argc, char **argv) {
FluentGlutApp(argc, argv)
.withDoubleBuffer().withRGBA().withAlpha().withDepth()
.at(200, 200).across(500, 500)
.named("My OpenGL/GLUT App")
.create();
}