C++链式编程fluent interface

引言

在查看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();
 }

猜你喜欢

转载自blog.csdn.net/weixin_43367756/article/details/126372664