Fluent interface

Материал из Википедии — свободной энциклопедии
Текущая версия страницы покане проверялась опытными участниками и может значительно отличаться отверсии, проверенной 20 февраля 2016 года; проверки требуют10 правок.
Перейти к навигацииПерейти к поиску

Текучий интерфейс (англ. fluent interface — в значении «плавный» или «гладкий» «интерфейс») в разработке программного обеспечения — способ реализацииобъектно-ориентированного API, нацеленный на повышениечитабельности исходного кода программы. Название придумано Эриком Эвансом и Мартином Фаулером.

Текучий интерфейс хорош тем, что упрощается множественный вызов методов одного объекта. Обычно это реализуется использованиемцепочки методов, передающих контекст вызова следующему звену (но текучий интерфейс влечет за собой нечто большее, чем просто цепочку методов[1]). Обычно, этот контекст:

  • определён с помощью значения, возвращаемого методом;
  • наследуется (в качестве нового контекста используется предыдущий);
  • прекращается возвращением ничего не значащего значения (void).

Такой стиль косвенно полезен повышением наглядности и интуитивности кода[источник не указан 5416 дней]. Однако может весьма пагубно сказаться на отладке, если цепочка действует как одно выражение, куда отладчик не всегда может установить промежуточнуюточку останова.

Содержание

Примеры

[править |править код]

Delphi (Object Pascal)

[править |править код]

Следующий пример показывает обычный класс и класс, реализующий текучий интерфейс, и различия в использовании. Пример написан на Delphi Object Pascal:

unitFluentInterface;interfacetypeIConfiguration=interfaceprocedureSetColor(Color:string);procedureSetHeight(height:integer);procedureSetLength(length:integer);procedureSetDepth(depth:integer);end;IConfigurationFluent=interfacefunctionSetColor(Color:string):IConfigurationFluent;functionSetHeight(height:integer):IConfigurationFluent;functionSetLength(length:integer):IConfigurationFluent;functionSetDepth(depth:integer):IConfigurationFluent;end;TConfiguration=class(TInterfacedObject,IConfiguration)privateFColor:string;FHeight:integer;FLength:integer;FDepth:integer;protectedprocedureSetColor(Color:string);procedureSetHeight(height:integer);procedureSetLength(length:integer);procedureSetDepth(depth:integer);end;TConfigurationFluent=class(TInterfacedObject,IConfigurationFluent)privateFColor:string;FHeight:integer;FLength:integer;FDepth:integer;protectedfunctionSetColor(Color:string):IConfigurationFluent;functionSetHeight(height:integer):IConfigurationFluent;functionSetLength(length:integer):IConfigurationFluent;functionSetDepth(depth:integer):IConfigurationFluent;publicclassfunctionNew:IConfigurationFluent;end;implementationprocedureTConfiguration.SetColor(Color:string);beginFColor:=Color;end;procedureTConfiguration.SetDepth(depth:integer);beginFDepth:=depth;end;procedureTConfiguration.SetHeight(height:integer);beginFHeight:=height;end;procedureTConfiguration.SetLength(length:integer);beginFLength:=length;end;classfunctionTConfigurationFluent.New:IConfigurationFluent;beginResult:=Create;end;functionTConfigurationFluent.SetColor(Color:string):IConfigurationFluent;beginFColor:=Color;Result:=Self;end;functionTConfigurationFluent.SetDepth(depth:integer):IConfigurationFluent;beginFDepth:=depth;Result:=Self;end;functionTConfigurationFluent.SetHeight(height:integer):IConfigurationFluent;beginFHeight:=height;Result:=Self;end;functionTConfigurationFluent.SetLength(length:integer):IConfigurationFluent;beginFLength:=length;Result:=Self;end;end.
varC,D:IConfiguration;E:IConfigurationFluent;begin{ Обычное использование:}C:=TConfiguration.Create;C.SetColor('blue');C.SetHeight(1);C.SetLength(2);C.SetDepth(3);{ обычная реализация, упрощенная с помощью инструкции with }D:=TConfiguration.Create;withDdobeginSetColor('blue');SetHeight(1);SetLength(2);SetDepth(3)end;{ использование реализации с текучим интерфейсом }E:=TConfigurationFluent.New.SetColor('Blue').SetHeight(1).SetLength(2).SetDepth(3);end;

C#

[править |править код]

Начиная сC# 3.5 и выше введены продвинутые способы реализации текучего интерфейса:

namespaceExample.FluentInterfaces{#region Standard ExamplepublicinterfaceIConfiguration{stringColor{set;}intHeight{set;}intLength{set;}intDepth{set;}}publicclassConfiguration:IConfiguration{stringcolor;intheight;intlength;intdepth;publicstringColor{set{color=value;}}publicintHeight{set{height=value;}}publicintLength{set{length=value;}}publicintDepth{set{depth=value;}}}#endregion#region Fluent ExamplepublicinterfaceIConfigurationFluent{IConfigurationFluentSetColor(stringcolor);IConfigurationFluentSetHeight(intheight);IConfigurationFluentSetLength(intlength);IConfigurationFluentSetDepth(intdepth);}publicclassConfigurationFluent:IConfigurationFluent{stringcolor;intheight;intlength;intdepth;publicIConfigurationFluentSetColor(stringcolor){this.color=color;returnthis;}publicIConfigurationFluentSetHeight(intheight){this.height=height;returnthis;}publicIConfigurationFluentSetLength(intlength){this.length=length;returnthis;}publicIConfigurationFluentSetDepth(intdepth){this.depth=depth;returnthis;}}#endregionpublicclassExampleProgram{publicstaticvoidMain(string[]args){// Обычный примерIConfigurationconfig=newConfiguration{Color="blue",Height=1,Length=2,Depth=3};// Пример текучего интерфейсаIConfigurationFluentfluentConfig=newConfigurationFluent().SetColor("blue").SetHeight(1).SetLength(2).SetDepth(3);}}}

C++

[править |править код]

Банальный пример вC++ — стандартныйiostream, где текучесть обеспечиваетсяперегрузкой операторов.

Примеробертки текучего интерфейса в C++:

// обычное заданиеclassGlutApp{private:intw_,h_,x_,y_,argc_,display_mode_;char**argv_;char*title_;public:GlutApp(intargc,char**argv){argc_=argc;argv_=argv;}voidsetDisplayMode(intmode){display_mode_=mode;}intgetDisplayMode(){returndisplay_mode_;}voidsetWindowSize(intw,inth){w_=w;h_=h;}voidsetWindowPosition(intx,inty){x_=x;y_=y;}voidsetTitle(constchar*title){title_=title;}voidcreate();};// обычное использованиеintmain(intargc,char**argv){GlutAppapp(argc,argv);app.setDisplayMode(GLUT_DOUBLE|GLUT_RGBA|GLUT_ALPHA|GLUT_DEPTH);// Set framebuffer paramsapp.setWindowSize(500,500);// Set window paramsapp.setWindowPosition(200,200);app.setTitle("My OpenGL/GLUT App");app.create();}// Обертка текучего интерфейсаclassFluentGlutApp:privateGlutApp{public:FluentGlutApp(intargc,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(intw,inth){setWindowSize(w,h);return*this;}FluentGlutApp&at(intx,inty){setWindowPosition(x,y);return*this;}FluentGlutApp&named(constchar*title){setTitle(title);return*this;}// без разницы, вести ли цепь после вызова create(), поэтому не возвращаем *thisvoidcreate(){GlutApp::create();}};// используем текучий интерфейсintmain(intargc,char**argv){FluentGlutAppapp(argc,argv).withDoubleBuffer().withRGBA().withAlpha().withDepth().at(200,200).across(500,500).named("My OpenGL/GLUT App");app.create();}

Java

[править |править код]

Некоторые API вJava реализуют такой интерфейс, напримерJava Persistence API:

publicCollection<Student>findByNameAgeGender(Stringname,intage,Gendergender){returnem.createNamedQuery("Student.findByNameAgeGender").setParameter("name",name).setParameter("age",age).setParameter("gender",gender).setFirstResult(1).setMaxResults(30).setHint("hintName","hintValue").getResultList();}

Библиотекаop4j позволяет использовать текучий интерфейс для выполнения вспомогательных задач, вродеитерированияструктур, конвертирования информации, фильтрации, и т. д.

String[]datesStr=newString[]{"12-10-1492","06-12-1978"};...List<Calendar>dates=Op.on(datesStr).toList().map(FnString.toCalendar("dd-MM-yyyy")).get();

Также, библиотекаMock-объект тестированияEasyMock активно использует этот стиль для предоставления удобного интерфейса.

CollectionmockCollection=EasyMock.createMock(Collection.class);EasyMock.expect(mockCollection.remove(null)).andThrow(newNullPointerException()).atLeastOnce();

PHP

[править |править код]

Пример реализации класса с текучим интерфейсом вPHP:

classCar{private$speed,$color,$doors;publicfunctionsetSpeed($speed){$this->speed=$speed;return$this;}publicfunctionsetColor($color){$this->color=$color;return$this;}publicfunctionsetDoors($doors){$this->doors=$doors;return$this;}}// Обычная реализация$myCar2=newCar();$myCar2->setSpeed(100);$myCar2->setColor('blue');$myCar2->setDoors(5);// Текучий интерфейс$myCar=newCar()->setSpeed(100)->setColor('blue')->setDoors(5);

JavaScript

[править |править код]

Пример реализации класса с текучим интерфейсом вJavaScript:

varCar=(function(){varspeed,color,doors,pub;functionsetSpeed(new_speed){speed=new_speed;returnpub;}functionsetColor(new_color){color=new_color;returnpub;}functionsetDoors(new_doors){doors=new_doors;returnpub;}pub={'setSpeed':setSpeed,'setColor':setColor,'setDoors':setDoors,};returnpub;})// Обычная реализацияmyCar2=Car();myCar2.setSpeed(100);myCar2.setColor('blue');myCar2.setDoors(5);// Текучий интерфейсmyCar=Car();myCar.setSpeed(100).setColor('blue').setDoors(5);

Также можно использовать иной подход:

var$=function(selector){if(this.$){returnnew$(selector);}if(typeofselector=="string"){this.init=document.getElementById(selector);}};$.prototype={text:function(text){if(!text){this.init.innerHTML;}this.init.innerHTML=text;returnthis;},css:function(style){for(variinstyle){this.init.style[i]=style[i];}returnthis;}};//пример использования:$('div').text('div').css({color:"red"});

Пример независящей от типа возвращаемого объекта реализации:

({foo:function(a){returna;}}).foo('foo').toUpperCase();

Примечания

[править |править код]
  1. MF Bliki: FluentInterface . Дата обращения: 26 октября 2010. Архивировано 8 марта 2021 года.

Ссылки

[править |править код]
Перейти к шаблону «Типы шаблонов проектирования»
Основные
Порождающие
Структурные
Поведенческие
Параллельного
программирования
Архитектурные
Шаблоны Java EE
Прочие шаблоны
Книги
Персоналии
Источник —https://ru.wikipedia.org/w/index.php?title=Fluent_interface&oldid=150321797
Категории:
Скрытые категории: