Delphi. Simple helper

Что такое хэлпер, можно прочитать здесь. Если кратко, то это класс расширяющий функциональность другого класса. Это немного похоже на наследование, но синтаксически выглядит по-другому, а именно:

type
  THelperForTObject = class helper for TObject
  public
    procedure Log(aMsg: string);
  end;

implementation

{ THelperForTObject }

procedure THelperForTObject.Log(aMsg: string);
begin
  Write(aMsg);
end;

Теперь мы можем в любом классе вызывать логгер, не правда ли удобно?

  o := TObject.Create();
  try
    o.Log('test logging');
    ReadLn;
  finally
    o.Free();
  end;

Области применения хэлперов.

Posted in Без рубрики | Comments Off on Delphi. Simple helper

Visitor pattern. Simple example

Простой пример шаблона визитер. Когда нужно вставить новую функциональность, не меняя класса.

unit uVisitor;

interface

uses
  SysUtils, System.Generics.Collections;

type
  TElement = class
  private
    FName: string;
  public
    constructor Create(aName: string);
    property Name: string read FName;
  end;

  TVisitor = class
  public
    procedure VisitElement(aElement: TElement); virtual; abstract;
  end;

  TConcreteVisitor = class(TVisitor)
  public
    procedure VisitElement(aElement: TElement); override;
  end;

  TObjectStructure = class
  private
    FObjectList: TObjectList<TElement>;
  public
    constructor Create();
    destructor Destroy; override;
    procedure Add(aElement: TElement);
    procedure Accept(aVisitor: TVisitor);
  end;

implementation

uses
  uMain;

{ TConcreteVisitor }

procedure TConcreteVisitor.VisitElement(aElement: TElement);
begin
  Main.mMemo.Lines.Add(Format('Name of element is %s', [aElement.Name]));
end;

{ TElement }

constructor TElement.Create(aName: string);
begin
  FName := aName;
end;

{ TObjectStructure }

procedure TObjectStructure.Accept(aVisitor: TVisitor);
var
  element: TElement;
begin
  for element in FObjectList do
    aVisitor.VisitElement(element);
end;

procedure TObjectStructure.Add(aElement: TElement);
begin
  FObjectList.Add(aElement);
end;

constructor TObjectStructure.Create;
begin
  FObjectList := TObjectList<TElement>.Create(true);
end;

destructor TObjectStructure.Destroy;
begin
  FObjectList.Free();
  inherited;
end;

end.

И теперь попробуем, что у нас получилось

procedure TMain.FormCreate(Sender: TObject);
var
  os: TObjectStructure;
begin
  os := TObjectStructure.Create();
  try
    os.Add(TElement.Create('Stas'));
    os.Add(TElement.Create('Helen'));
    os.Accept(TConcreteVisitor.Create());
  finally
    os.Free();
  end;
end;

Также, интересная статья на хабре

Или так…

unit uVisitor;

interface

uses
  SysUtils, System.Generics.Collections;

type
  TVisitor = class;

  TElement = class
  private
    FName: string;
  public
    constructor Create(aName: string);
    property Name: string read FName;
    procedure Accept(aVisitor: TVisitor); virtual; abstract;
  end;

  TConcreteElement = class(TElement)
  public
    procedure Accept(aVisitor: TVisitor); override;
  end;

  TVisitor = class
  public
    procedure VisitElement(aElement: TElement); virtual; abstract;
  end;

  TConcreteVisitor = class(TVisitor)
  public
    procedure VisitElement(aElement: TElement); override;
  end;

  TObjectStructure = class
  private
    FObjectList: TObjectList<TElement>;
  public
    constructor Create();
    destructor Destroy; override;
    procedure Add(aElement: TElement);
    procedure Accept(aVisitor: TVisitor);
  end;

implementation

uses
  uMain;

{ TConcreteVisitor }

procedure TConcreteVisitor.VisitElement(aElement: TElement);
begin
  Main.mMemo.Lines.Add(Format('Name of element is %s', [aElement.Name]));
end;

{ TElement }

constructor TElement.Create(aName: string);
begin
  FName := aName;
end;

{ TObjectStructure }

procedure TObjectStructure.Accept(aVisitor: TVisitor);
var
  element: TElement;
begin
  for element in FObjectList do
    element.Accept(aVisitor);
//    aVisitor.VisitElement(element);
end;

procedure TObjectStructure.Add(aElement: TElement);
begin
  FObjectList.Add(aElement);
end;

constructor TObjectStructure.Create;
begin
  FObjectList := TObjectList<TElement>.Create(true);
end;

destructor TObjectStructure.Destroy;
begin
  FObjectList.Free();
  inherited;
end;

{ TConcreteElement }

procedure TConcreteElement.Accept(aVisitor: TVisitor);
begin
  aVisitor.VisitElement(Self);
end;

end.
Posted in Без рубрики | Comments Off on Visitor pattern. Simple example

Delphi. HashMap

Из проекта

uses
  System.SysUtils, System.Classes, System.Generics.Collections, Rtti, xsuperjson, xsuperobject, System.TypInfo, System.Generics.Defaults;
{hash map for objects on TDictionary and TList<>}
  THashMap<K, V> = class
  private
    FDictionary: TDictionary<K, TList<TPair<K, V>>>;
    FKeyComparer: IComparer<K>;
    FOwnsObjects: Boolean;
    function GetItems(aKey: K): V;
    procedure SetItems(aKey: K; const aValue: V);
  public
    constructor Create(aKeyComparer: IComparer<K>; aOwnsObjects: Boolean = true);
    destructor Destroy; override;
    procedure Clear();
    procedure Add(aKey: K; aValue: V);
    procedure Remove(aKey: K);
    function ContainsKey(aKey: K): Boolean;
    property Items[aKey: K]: V read GetItems write SetItems; default;
  end;
{ THashMap }

procedure THashMap<K, V>.Add(aKey: K; aValue: V);
begin
  if not FDictionary.ContainsKey(aKey) then
    FDictionary.Add(aKey, TList<TPair<K, V>>.Create());

  FDictionary[aKey].Add(TPair<K, V>.Create(aKey, aValue));
end;

procedure THashMap<K, V>.Clear;
var
  key: K;
begin
  for key in FDictionary.Keys do
    Remove(key);
end;

function THashMap<K, V>.ContainsKey(aKey: K): Boolean;
begin
  Result := FDictionary.ContainsKey(aKey)
end;

constructor THashMap<K, V>.Create(aKeyComparer: IComparer<K>; aOwnsObjects: Boolean = true);
begin
  FDictionary := TDictionary<K, TList<TPair<K, V>>>.Create();
  EnsureNotNull(aKeyComparer, 'aKeyComparer');
  FKeyComparer := aKeyComparer;
  FOwnsObjects := aOwnsObjects;
end;

destructor THashMap<K, V>.Destroy;
begin
  Clear();
  FDictionary.Free();
  inherited;
end;

function THashMap<K, V>.GetItems(aKey: K): V;
var
  p: TPair<K, V>;
  i: integer;
begin
  if FDictionary[aKey].Count = 1 then
  begin
    p := FDictionary[aKey].Items[0];
    Result := p.Value;
    Exit;
  end
  else if FDictionary[aKey].Count > 1 then
  begin
    // compare keys in list
    for i := 0 to FDictionary[aKey].Count - 1 do
    begin
      p := FDictionary[aKey][i];
      if FKeyComparer.Compare(p.Key, aKey) = 0 then
      begin
        Result := p.Value;
        Exit;
      end;
    end;
  end;
end;

procedure THashMap<K, V>.Remove(aKey: K);
var
  i: integer;
  list: TList<TPair<K, V>>;
begin
  if not FDictionary.ContainsKey(aKey) then
    raise Exception.Create('cannnot remove, item not found');

  list := FDictionary[aKey];
  for i := list.Count - 1 downto 0 do
  begin
    if (FOwnsObjects) and (TValueTypeChecker<V>.IsValueAnObject(list[i].Value)) then
      PObject(@list[i].Value)^.Free();
  end;

  FreeAndNil(list);

  FDictionary.Remove(aKey);
end;

procedure THashMap<K, V>.SetItems(aKey: K; const aValue: V);
var
  p: TPair<K, V>;
  i: integer;
begin
  if FDictionary[aKey].Count = 1 then
  begin
    p := FDictionary[aKey].Items[0];
    FDictionary[aKey].Remove(p);
    FDictionary[aKey].Add(TPair<K, V>.Create(aKey, aValue));
    Exit;
  end
  else if FDictionary[aKey].Count > 1 then
  begin
    // compare keys in list
    for i := 0 to FDictionary[aKey].Count - 1 do
    begin
      p := FDictionary[aKey][i];
      if FKeyComparer.Compare(p.Key, aKey) = 0 then
      begin
        FDictionary[aKey].Remove(p);
        FDictionary[aKey].Add(TPair<K, V>.Create(aKey, aValue));
        Exit;
      end;
    end;
  end;
end;
Posted in Без рубрики | Comments Off on Delphi. HashMap

SVN. Return to the previous state

According to stackOverflow

svn update
svn merge -r 150:140 .
svn commit -m "Rolled back to r140"

Posted in Без рубрики | Comments Off on SVN. Return to the previous state

Delphi. Dependency Injection With Spring

Этот пример можно найти в библиотеке Spring for Delphi, где-то примерно здесь

C:\Work\DSeattle\libs\sglienke-spring4d\Samples\IntroToDependencyInjection\6-UseContainer

Как это работает? Для начала нам нужно зарегистрировать в контейнере классы

unit uRegistrations;

interface

uses
  Spring.Container;

procedure RegisterTypes(const container: TContainer);

implementation

uses
  uOrderEntry,
  uOrderProcessor,
  uOrderValidator;

procedure RegisterTypes(const container: TContainer);
begin
  container.RegisterType<TOrderEntry>;
  container.RegisterType<TOrderValidator>;

  container.Build;
end;

end.

Теперь, в основном коде программы мы делаем примерно что-то такое…

...
  RegisterTypes(GlobalContainer);
  Order := TOrder.Create;
  try
    OrderValidator := GlobalContainer.Resolve<IOrderValidator>;
    OrderEntry := GlobalContainer.Resolve<IOrderEntry>;
    OrderProcessor := TOrderProcessor.Create(OrderValidator, OrderEntry);
    if OrderProcessor.ProcessOrder(Order) then
      Writeln('Order successfully processed....');
  finally
    Order.Free;
  end;
...

Как видно из кода, мы просим контейнер дать инстанс, реализующий интерфейс и далее, просто работаем с ним.

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

Таким образом, достигнута слабая связность, что довольно удобно при перекомпоновке проекта.

Posted in Без рубрики | Comments Off on Delphi. Dependency Injection With Spring

Delphi. IDE Git Client

В Delphi есть довольно простой Git клиент, который позволят делать базовые операции commit, push, просмотр лога и др. Вызывается он из контекстного меню и выглядит примерно так…

Как его настроить и использовать читайте здесь и здесь

Posted in Без рубрики | Comments Off on Delphi. IDE Git Client

Delphi. Serialization / Deserialization. XML / JSON

XML

OmniXML is a smart way to serialize smth.

First point, your objects should be derived from

TPersistent, TCollection or TCollection item.

Second point. Saved information should be in published section.

I do it like this

uses
OmniXML, OmniXMLPersistent

Saving


var
o : TSomeObject; // derived from TPersistent
...
TOmniXMLWriter.SaveToFile( o, 'c:\path\file.xml', pfAttributes, ofIndent );

Loading

TOmniXMLWriter.LoadFromFile( o, 'c:\path\file.xml' ); 

JSON

I use superobject library, example from github

  TTest = class // Field, Property Support
  private
    FB: String;
    FSubObj: TSubObj;
    FSubRec: TSubRec;
    FTestSets: TTestSets;
    FH: TDateTime;
    FJ: TDate;
    FK: TTime;
    FList: TObjectList<TSubObj>; // or TList<>; But only object types are supported
  public
    A: Integer;
    B: TTestSet;
    C: Boolean;
    property D: String read FB write FB;
    property E: TSubRec read FSubRec write FSubRec;
    property F: TSubObj read FSubObj write FSubObj;
    property G: TTestSets read FTestSets write FTestSets;
    property H: TDateTime read FH write FH;
    property J: TDate read FJ write FJ;
    property K: TTime read FK write FK;
    property L: TObjectList<TSubObj> read FList write FList;
  end;
  
  TTestRec = record // Only Field Support
    A: Integer;
    B: TTestSet;
    C: Boolean;
    D: String;
    E: TSubRec;
    F: TSubObj;
    G: TTestSets;
    H: TDateTime;
    J: TDate;
    K: TTime;
    L: TObjectList<TSubObj>; // or TList<>; But only object types are supported
  end;
  
  implementation
  ...
  
  var 
    Parse: TTest; // For Class;
    S: String;
  begin
    Parse := TTest.FromJSON('{"A": 1, "B": 0, "C": true, "D": "Hello", "E":{"A": 3, "B": "Delphi"}, "F": {"A": 4, "B": 5}, "G": [0,2], "H": "2014-05-03T03:25:05.059", "J": "2014-05-03", "K": "03:25:05", "L":[{"A": 4, "B": 5},{"A": 6, "B": 7}] }');
    S := Parse.AsJSON;
  end;
  
  
  ...
  var
    Parse: TTestRec; // For Record;
    S: String;
  begin
    Parse := TJSON.Parse<TTestRec>('{"A": 1, "B": 0, "C": true, "D": "Hello", "E":{"A": 3, "B": "Delphi"}, "F": {"A": 4, "B": 5}, "G": [0,2], "H": "2014-05-03T03:25:05.059", "J": "2014-05-03", "K": "03:25:05", "L":[{"A": 4, "B": 5},{"A": 6, "B": 7}]}');  
    S := TJSON.Stringify<TTestRec>(Parse);
  end;

Also fix by krapotkin

Posted in Без рубрики | Comments Off on Delphi. Serialization / Deserialization. XML / JSON

Delphi. Lambda. Anonymous methods

Example

program LambdaExamples;

{$APPTYPE CONSOLE}

{$R *.res}

uses
  System.SysUtils;

type
  TSayHello = reference to function(aName: string): string;

  TFuncOfIntToString = reference to function(x: Integer): string;

  TFuncOfString = reference to function(a, b: string): string;

  TMethodReference = reference to procedure(aArg: string);

  TSomeClass = class
    procedure Foo(aArg: string);
  end;

var
  myFunc: TFuncOfIntToString;
  concater: TFuncOfString;
  someClassInstance: TSomeClass;
  m: TMethodReference;
  sayHello: TSayHello;


// lets say we have following functions
procedure AnalyzeProcedure(func: TFuncOfIntToString);
begin
  // use argument
  WriteLn(func(12));
end;

function MakeConcat(y: Integer): TFuncOfString;
begin
  Result :=
    function(a, b: string): string
    begin
      Result := Format('%s %s %s', [a, b, y.ToString()]);
    end;
end;

{ TSomeClass }

procedure TSomeClass.Foo(aArg: string);
begin
  Writeln(aArg);
end;

begin

   // 1. lets say we in context of some class and we need to do
   // smth fast without overhead of instantiate new class
   // we can do it like this
  sayHello :=
    function(aName: string): string
    begin
      Result := Format('hello %s', [aName]);
    end;
  WriteLn(sayHello('Stan'));

  //2.  use lambda directly in another function
  AnalyzeProcedure(
    function(x: Integer): string
    begin
      Result := IntToStr(x);
    end);

  //3.  put lambda to variable
  myFunc :=
    function(x: Integer): string
    begin
      Result := IntToStr(x);
    end;

  AnalyzeProcedure(myFunc);

  //4.  --- Closure
  concater := MakeConcat(123);
  WriteLn(concater('a', 'b'));

  //5.  reference to method
  someClassInstance := TSomeClass.Create();
  try
    m := someClassInstance.Foo;
    m('this is reference to method');

    // ACHTUNG !!! DONT' DO LIKE THIS
    // someClassInstance.Foo := m;  << DANGER OF MEMORY LEAKS
  finally
    someClassInstance.Free();
  end;

  ReadLn;
end.
Posted in Без рубрики | Comments Off on Delphi. Lambda. Anonymous methods

Delphi. Jcl. HashMaps

Example

program JediHashMaps;

{$APPTYPE CONSOLE}

{$R *.res}

uses
  System.SysUtils,
  JclContainerIntf,
  JclHashMaps;

var
  h: IJclIntegerIntegerMap;

const
  key = 1;
  value = 123;

begin
  h := TJclIntegerIntegerHashMap.Create(10);
  h.PutValue(key, value);

  if h.ContainsKey(key) then
    Writeln(Format('contains key %s with value %s', [key.ToString(), h.Items[key].ToString()]));

  ReadLn;
end.
Posted in Без рубрики | Comments Off on Delphi. Jcl. HashMaps

Icons. Collections

icons8

Posted in Без рубрики | Comments Off on Icons. Collections