Интернет магазин китайских планшетных компьютеров



Компьютеры - Fluent interface - Примеры

13 мая 2011


Оглавление:
1. Fluent interface
2. Примеры



Delphi

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

unit FluentInterface;
 
interface
 
type
  IConfiguration = interface
    procedure SetColor;
    procedure SetHeight;
    procedure SetLength;
    procedure SetDepth;
  end;
 
  IConfigurationFluent = interface
    function SetColor: IConfigurationFluent;
    function SetHeight: IConfigurationFluent;
    function SetLength: IConfigurationFluent;
    function SetDepth: IConfigurationFluent;
  end;
 
  TConfiguration = class
  private
    FColor: string;
    FHeight: integer;
    FLength: integer;
    FDepth: integer;
  protected
    procedure SetColor;
    procedure SetHeight;
    procedure SetLength;
    procedure SetDepth;
  end;
 
  TConfigurationFluent = class
  private
    FColor: string;
    FHeight: integer;
    FLength: integer;
    FDepth: integer;
  protected
    function SetColor: IConfigurationFluent;
    function SetHeight: IConfigurationFluent;
    function SetLength: IConfigurationFluent;
    function SetDepth: IConfigurationFluent;
  public
    class function New: IConfigurationFluent;
  end;
 
implementation
 
procedure TConfiguration.SetColor;
begin
  FColor := Color;
end;
 
procedure TConfiguration.SetDepth;
begin
  FDepth := depth;
end;
 
procedure TConfiguration.SetHeight;
begin
  FHeight := height;
end;
 
procedure TConfiguration.SetLength;
begin
  FLength := length;
end;
 
class function TConfigurationFluent.New: IConfigurationFluent;
begin
  Result := Create;
end;
 
function TConfigurationFluent.SetColor: IConfigurationFluent;
begin
  FColor := Color;
  Result := Self;
end;
 
function TConfigurationFluent.SetDepth: IConfigurationFluent;
begin
  FDepth := depth;
  Result := Self;
end;
 
function TConfigurationFluent.SetHeight: IConfigurationFluent;
begin
  FHeight := height;
  Result := Self;
end;
 
function TConfigurationFluent.SetLength: IConfigurationFluent;
begin
  FLength := length;
  Result := Self;
end;
 
end.
var C, D: IConfiguration;
    E: IConfigurationFluent;
begin
  { Обычное использование:}
  C := TConfiguration.Create;
  C.SetColor;
  C.SetHeight;
  C.SetLength;
  C.SetDepth;
 
  { обычная реализация, упрощенная с помощью инструкции with }
  D := TConfiguration.Create;
  with D do begin
    SetColor;
    SetHeight;
    SetLength;
    SetDepth
  end;
 
  { использование реализации с текучим интерфейсом }
  E := TConfigurationFluent.New
       .SetColor
       .SetHeight
       .SetLength
       .SetDepth;
end;

C#

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

namespace Example.FluentInterfaces
{
    #region Standard Example
 
    public interface IConfiguration
    {
        string Color { set; }
        int Height { set; }
        int Length { set; }
        int Depth { set; }
    }
 
    public class Configuration : IConfiguration
    {
        string color;
        int height;
        int length;
        int depth;
 
        public string Color
        {
            set { color = value; }
        }
 
        public int Height
        {
            set { height = value; }
        }
 
        public int Length
        {
            set { length = value; }
        }
 
        public int Depth
        {
            set { depth = value; }
        }
    }
 
    #endregion
 
    #region Fluent Example
 
    public interface IConfigurationFluent
    {
        IConfigurationFluent SetColor;
        IConfigurationFluent SetHeight;
        IConfigurationFluent SetLength;
        IConfigurationFluent SetDepth;
    }
 
    public class ConfigurationFluent : IConfigurationFluent
    {
        string color;
        int height;
        int length;
        int depth;
 
        public IConfigurationFluent SetColor
        {
            this.color = color;
            return this;
        }
 
        public IConfigurationFluent SetHeight
        {
            this.height = height;
            return this;
        }
 
        public IConfigurationFluent SetLength
        {
            this.length = length;
            return this;
        }
 
        public IConfigurationFluent SetDepth
        {
            this.depth = depth;
            return this;
        }
    }
 
    #endregion
 
    public class ExampleProgram
    {
        public static void Main
        {
            // Обычный пример
            IConfiguration config = new Configuration
            {
                Color = "blue",
                Height = 1,
                Length = 2,
                Depth = 3
            };
 
            // Пример текучего интерфейса
            IConfigurationFluent fluentConfig =
                  new ConfigurationFluent.SetColor
                                           .SetHeight
                                           .SetLength
                                           .SetDepth;
        }
    }
}

C++

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

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

 // обычное задание
 class GlutApp {
 private:
     int w_, h_, x_, y_, argc_, display_mode_;
     char **argv_;
     char *title_;
 public:
     GlutApp {
         argc_ = argc;
         argv_ = argv;
     }
     void setDisplayMode {
         display_mode_ = mode;
     }
     int getDisplayMode {
         return display_mode_;
     }
     void setWindowSize {
         w_ = w;
         h_ = h;
     }
     void setWindowPosition {
         x_ = x;
         y_ = y;
     }
     void setTitle {
         title_ = title;
     }
     void create;
 };
 // обычное использование
 int main {
     GlutApp app;
     app.setDisplayMode; // Set framebuffer params
     app.setWindowSize; // Set window params
     app.setWindowPosition;
     app.setTitle;
     app.create;
 }
 
 // Обертка текучего интерфейса
 class FluentGlutApp : private GlutApp {
 public:
     FluentGlutApp : GlutApp {} // наследуем родительский конструктор
     FluentGlutApp &withDoubleBuffer {
         setDisplayMode | GLUT_DOUBLE);
         return *this;
     }
     FluentGlutApp &withRGBA {
         setDisplayMode | GLUT_RGBA);
         return *this;
     }
     FluentGlutApp &withAlpha {
         setDisplayMode | GLUT_ALPHA);
         return *this;
     }
     FluentGlutApp &withDepth {
         setDisplayMode | GLUT_DEPTH);
         return *this;
     }
     FluentGlutApp &across {
         setWindowSize;
         return *this;
     }
     FluentGlutApp &at {
         setWindowPosition;
         return *this;
     }
     FluentGlutApp &named {
         setTitle;
         return *this;
     }
     // без разницы, вести ли цепь после вызова create, поэтому не возвращаем *this
     void create {
         GlutApp::create;
     }
 };
 // используем текучий интерфейс
 int main {
     FluentGlutApp app
         .withDoubleBuffer.withRGBA.withAlpha.withDepth
         .at.across
         .named;
     app.create;
 }

Java

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

public Collection<Student> findByNameAgeGender {
    return em.createNamedQuery
             .setParameter
             .setParameter
             .setParameter
             .setFirstResult
             .setMaxResults
             .setHint
             .getResultList;
}


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

String datesStr = new String {"12-10-1492", "06-12-1978" };
...
List<Calendar> dates = 
    Op.on.toList.map).get;


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

Collection mockCollection = EasyMock.createMock;
EasyMock.expect).andThrow).atLeastOnce;

PHP

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

class Car {
        private $speed;
        private $color;
        private $doors;
 
        public function setSpeed{
                $this->speed = $speed;
                return $this;
        }
 
        public function setColor {
                $this->color = $color;
                return $this;
        }
 
        public function setDoors {
                $this->doors = $doors;
                return $this;
        }
}
 
// Обычная реализация
$myCar2 = new Car;
$myCar2->setSpeed;
$myCar2->setColor;
$myCar2->setDoors;
 
// Текучий интерфейс
$myCar = new Car;
$myCar->setSpeed->setColor->setDoors;

JavaScript

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

var Car = {
 
        var speed, color, doors, pub;
 
        function setSpeed {
                speed = new_speed;
                return pub;
        }
 
        function setColor {
                color = new_color;
                return pub;
        }
 
        function setDoors {
                doors = new_doors;
                return pub;
        }
 
        pub = {
                'setSpeed': setSpeed,
                'setColor': setColor,
                'setDoors': setDoors,
        };
 
        return pub;
 
})
 
// Обычная реализация
myCar2 = Car;
myCar2.setSpeed;
myCar2.setColor;
myCar2.setDoors;
 
// Текучий интерфейс
myCar = Car;
myCar.setSpeed.setColor.setDoors;

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

var $ = function {
    if {
        return new $;
    }
    if {
        this.init = document.getElementById;
    }
};
 
$.prototype = {
    text: function {
        if{
           this.init.innerHTML;
        }
        this.init.innerHTML = text;
        return this;
    },
    css: function {
        for{
           this.init.style = style;
        }
        return this;
    }
};
//пример использования:
$.text.css;

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

({
    foo: function  {
        return a;
    }
}).foo.toUpperCase;


Просмотров: 1965


<<< ActiveRecord
Model-View-Controller >>>