Logo

9 декабря 2014 г.

Этюд 6. Кантование свойства-кортежа

Продолжая тему кантования, рассмотрим его применение к кортежам — свойствам, инкапсулирующим несколько параметров.

На Delphi

В Delphi нет возможности описать свойство, выдающее или изменяющее несколько параметров за раз, не объединив их в запись. Соответствующую функциональность приходится эмулировать процедурами:
type
  TBounds = record
    Left, Top, Width, Height: Integer;
  end;

  TSubControl = 0..1;

  TControl = class
  private
    FSubControlBounds: array[TSubControl] of TBounds;
  public
    procedure GetSubControlBounds(Index: TSubControl;
      var Left, Top, Width, Height: Integer); virtual;
    procedure SetSubControlBounds(Index: TSubControl;
      Left, Top, Width, Height: Integer); virtual;
  end;

procedure TControl.GetSubControlBounds(Index: TSubControl;
  var Left, Top, Width, Height: Integer);
begin
  Left := FSubControlBounds[Index].Left;
  Top := FSubControlBounds[Index].Top;
  Width := FSubControlBounds[Index].Width;
  Height := FSubControlBounds[Index].Height;
end;

procedure TControl.SetSubControlBounds(Index: TSubControl;
  Left, Top, Width, Height: Integer);
begin
  FSubControlBounds[Index].Left := Left;
  FSubControlBounds[Index].Top := Top;
  FSubControlBounds[Index].Width := Width;
  FSubControlBounds[Index].Height := Height;
end;

// использование
procedure MoveSubControl(Control: TControl);
var
  X, Y, W, H: Integer;
begin
  Control.GetSubControlBounds(1, X, Y, W, H);
  Inc(X, W);
  Inc(Y, H div 2);
  Control.SetSubControlBounds(1, X, Y, W, H);
end;

На Канторе

Задача легко решается свойствами-кортежами, к которым тоже применимо кантование:
public final class Bounds of
  public final var Core:LongInt Left, Top, Width, Height;
end;

public final class SubControl = 0..1;

public class Control of
  var Bounds[SubControl] subControlBounds;
  // либо var Bounds subControlBounds[SubControl];
  // кантование применимо и здесь

  public final Bounds(SubControl index; // out-свойство
    out Core:LongInt left, top, width, height)
  of
    scb = subControlBounds[index];
    return scb.left, scb.top, scb.width, scb.height;
  end;

  public Bounds(SubControl index; // in-свойство
    Core:LongInt left, top, width, height)
  of
    scb partial subControlBounds(index);
    scb.left = left;
    scb.top = top;
    scb.width = width;
    scb.height = height;
  end;
end;

// использование
moveSubControl(Control control) of
  var (x, y, w, h) = control.Bounds[1]; // кантование out-свойства
  x += w;
  y += h \ 2;
  control.Bounds(1) = [x, y, w, h]; // кантование in-свойства
end;
При кантовании out-свойства работает вывод типов, что упрощает объявление переменных, значение которых берется из свойства-кортежа.

Экспериментальная форма оператора partial без знака «равно» аналогична прошлому этюду.

Комментариев нет :

Отправить комментарий

Выбрав в выпадающем списке пункт «Имя/URL», можно оставить комментарий от своего имени без предварительной регистрации.