Fluent interface
Fluent interface (біжучий чи текучий інтерфейс) в програмуванні — спосіб конструювання об'єктно-орієнтованого API, в якому читабельність коду є близькою до звичайного прозового тексту. Термін вперше був застосований Еріком Евансом та Мартіном Фаулером. Нижче подано приклад для фреймворку тестування JMock: [1].
mock.expects(once()).method("m").with( or(stringContains("hello"), stringContains("howdy")) );
Історія
Термін "fluent interface" з'явився в кінці 2005, хоча подібний підхід використовувався в Smalltalk ще в 1970-х, та в інших в 1980-их. Типовим прикладом є бібліотека iostream в мові C++, де використовуються оператори <<
та >>
для передачі повідомлень, багатократної пересилки даних до одного і того самого об'єкта.
Приклади
C++
Нижче наведено приклад, де fluent interface обгортка застосована поверх більш традиційного інтерфейсу C++:
// Звичайне визначення 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(){;} }; // Базове використання int main(int argc, char **argv) { GlutApp app(argc, argv); app.setDisplayMode(GLUT_DOUBLE|GLUT_RGBA|GLUT_ALPHA|GLUT_DEPTH); app.setWindowSize(500, 500); app.setWindowPosition(200, 200); app.setTitle("My OpenGL/GLUT App"); app.create(); } // "fluent interface" обгортка class FluentGlutApp : private GlutApp { public: FluentGlutApp(int argc, char **argv) : GlutApp(argc, argv) {} 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; } // Ланцюжок після create() немає змісту, тому не повертаємо *this void create() { GlutApp::create(); } }; // Використання "fluent interface" 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(); }
Python
В мові Python використовують повернення `self` в методі.
class Poem(object): def __init__(self, content): self.content = content def indent(self, spaces): self.content = " " * spaces + self.content return self def suffix(self, content): self.content = self.content + " - " + content return self
>>> Poem("Road Not Travelled").indent(4).suffix("Robert Frost").content ' Road Not Travelled - Robert Frost'
Примітки
- ↑ FluentInterface [Архівовано 8 березня 2021 у Wayback Machine.], Martin Fowler, 20-12-2005