Einzelnen Beitrag anzeigen

Benutzerbild von Sir Rufo
Sir Rufo

Registriert seit: 5. Jan 2005
Ort: Stadthagen
9.454 Beiträge
 
Delphi 10 Seattle Enterprise
 
#3

AW: Brauche Hilfe bei der Aufnahme und Umsetzung von Mailregeln

  Alt 18. Dez 2015, 17:44
Diese Filter sind ja ein Standard-Pattern, darum hat da auch schon jemand ein Standard-Pattern definiert:

Bei Google suchenSpecification Pattern

Mit diesem Pattern kann man sich den Filter zusammenbauen.

In Delphi sieht das dann so aus
Delphi-Quellcode:
unit Patterns.Specifications;

interface

uses
  System.SysUtils;

type
  ISpecification = interface
    [ '{664ED0AE-42AF-4B5A-9A9F-D6C7565D995C}' ]
    function IsSatisfiedBy( const candidate: TObject ): Boolean;
    function &And( other: ISpecification ): ISpecification;
    function &Or( other: ISpecification ): ISpecification;
    function &Not( ): ISpecification;
  end;

  TCompositeSpecification = class abstract( TInterfacedObject, ISpecification )
  public
    function IsSatisfiedBy( const candidate: TObject ): Boolean; virtual; abstract;
    function &And( other: ISpecification ): ISpecification;
    function &Or( other: ISpecification ): ISpecification;
    function &Not( ): ISpecification;
  end;

  TAndSpecification = class( TCompositeSpecification )
  private
    FLeft, FRight: ISpecification;
  public
    constructor Create( Left, Right: ISpecification );
    function IsSatisfiedBy( const candidate: TObject ): Boolean; override;
  end;

  TOrSpecification = class( TCompositeSpecification )
  private
    FLeft, FRight: ISpecification;
  public
    constructor Create( Left, Right: ISpecification );
    function IsSatisfiedBy( const candidate: TObject ): Boolean; override;
  end;

  TNotSpecification = class( TCompositeSpecification )
  private
    FOther: ISpecification;
  public
    constructor Create( other: ISpecification );
    function IsSatisfiedBy( const candidate: TObject ): Boolean; override;
  end;

  TDelegatedSpecification = class( TCompositeSpecification )
  private
    FDelegate: TPredicate<TObject>;
  public
    constructor Create( ADelegate: TPredicate<TObject> );
    function IsSatisfiedBy( const candidate: TObject ): Boolean; override;
  end;

  TDelegatedSpecification<T: class> = class( TDelegatedSpecification )
  public
    constructor Create( ADelegate: TPredicate<T> );
  end;

implementation

{ TCompositeSpecification }

function TCompositeSpecification.&And( other: ISpecification ): ISpecification;
begin
  Result := TAndSpecification.Create( self, other );
end;

function TCompositeSpecification.&Not: ISpecification;
begin
  Result := TNotSpecification.Create( self );
end;

function TCompositeSpecification.&Or( other: ISpecification ): ISpecification;
begin
  Result := TOrSpecification.Create( self, other );
end;

{ TAndSpecification }

constructor TAndSpecification.Create( Left, Right: ISpecification );
begin
  inherited Create;
  FLeft := Left;
  FRight := Right;
end;

function TAndSpecification.IsSatisfiedBy( const candidate: TObject ): Boolean;
begin
  Result := FLeft.IsSatisfiedBy( candidate ) and FRight.IsSatisfiedBy( candidate );
end;

{ TOrSpecification }

constructor TOrSpecification.Create( Left, Right: ISpecification );
begin
  inherited Create;
  FLeft := Left;
  FRight := Right;
end;

function TOrSpecification.IsSatisfiedBy( const candidate: TObject ): Boolean;
begin
  Result := FLeft.IsSatisfiedBy( candidate ) or FRight.IsSatisfiedBy( candidate );
end;

{ TNotSpecification }

constructor TNotSpecification.Create( other: ISpecification );
begin
  inherited Create;
  FOther := other;
end;

function TNotSpecification.IsSatisfiedBy( const candidate: TObject ): Boolean;
begin
  Result := not FOther.IsSatisfiedBy( candidate );
end;

{ TDelegatedSpecification }

constructor TDelegatedSpecification.Create( ADelegate: TPredicate<TObject> );
begin
  inherited Create( );
  FDelegate := ADelegate;
end;

function TDelegatedSpecification.IsSatisfiedBy( const candidate: TObject ): Boolean;
begin
  Result := FDelegate( candidate );
end;

{ TDelegatedSpecification<T> }

constructor TDelegatedSpecification<T>.Create( ADelegate: TPredicate<T> );
begin
  inherited Create(
    function( o: TObject ): Boolean
    begin
      Result := true
      {} and ( o is T )
      {} and ADelegate( o as T );
    end );
end;

end.
Und würde so verwendet
Delphi-Quellcode:
program dp_187656;

{$APPTYPE CONSOLE}
{$R *.res}

uses
  System.DateUtils,
  System.Generics.Collections,
  System.SysUtils,
  Patterns.Specifications in 'Patterns.Specifications.pas';

type
  TFoo = class
  private { fields }
    FName : string;
    FDateOfBirth: TDateTime;
    function GetAge: Integer;
  public { properties }
    property name : string read FName write FName;
    property DateOfBirth: TDateTime read FDateOfBirth write FDateOfBirth;
    property Age : Integer read GetAge;
  public { constructors }
    constructor Create( const AName: string; const ADateOfBirth: TDateTime );
  public { methods }
    function ToString: string; override;
  end;

  { TFoo }

constructor TFoo.Create( const AName: string; const ADateOfBirth: TDateTime );
begin
  inherited Create;
  FName := AName;
  FDateOfBirth := ADateOfBirth;
end;

function TFoo.GetAge: Integer;
begin
  Result := YearsBetween( DateOfBirth, Date );
end;

function TFoo.ToString: string;
begin
  Result := string.Format( '%s, geb. %s (%d)', [ FName, DateToStr( FDateOfBirth ), Age ] );
end;

procedure PrintFooListSpec( const ATitle: string; AFoos: TEnumerable<TFoo>; ASpecification: ISpecification = nil );
var
  lFoo: TFoo;
begin
  if not Assigned( AFoos )
  then
    raise EArgumentNilException.Create( 'AFoos' );

  WriteLn( ATitle );

  for lFoo in AFoos do
    begin
      if not Assigned( ASpecification ) or ASpecification.IsSatisfiedBy( lFoo )
      then
        WriteLn( ' ', lFoo.ToString( ) );
    end;

  WriteLn;
end;

procedure Test1;
var
  lFooStartWithA : ISpecification;
  lFooNameContains_e: ISpecification;
  lFooOlderThan18 : ISpecification;
  lFoos : TObjectList<TFoo>;
  lFoo : TFoo;
begin
  lFooStartWithA := TDelegatedSpecification<TFoo>.Create(
    function( o: TFoo ): Boolean
    begin
      Result := o.Name.StartsWith( 'A' );
    end );

  lFooNameContains_e := TDelegatedSpecification<TFoo>.Create(
    function( o: TFoo ): Boolean
    begin
      Result := o.Name.Contains( 'e' );
    end );

  lFooOlderThan18 := TDelegatedSpecification<TFoo>.Create(
    function( o: TFoo ): Boolean
    begin
      Result := o.Age >= 18;
    end );

  lFoos := TObjectList<TFoo>.Create( );
  try

    lFoos.Add( TFoo.Create( 'Albert', EncodeDate( 1969, 1, 1 ) ) );
    lFoos.Add( TFoo.Create( 'Anton', EncodeDate( 2001, 1, 1 ) ) );
    lFoos.Add( TFoo.Create( 'Horst', EncodeDate( 1975, 1, 1 ) ) );
    lFoos.Add( TFoo.Create( 'Peter', EncodeDate( 1960, 1, 1 ) ) );

    PrintFooListSpec( 'ALLE', lFoos );
    PrintFooListSpec( 'Alle mit A*', lFoos, lFooStartWithA );
    PrintFooListSpec( 'Alle mit *e*', lFoos, lFooNameContains_e );
    PrintFooListSpec( 'Alle älter als 18', lFoos, lFooOlderThan18 );
    PrintFooListSpec( 'Alle älter als 18 und mit A*', lFoos, lFooOlderThan18.&And( lFooStartWithA ) );
    PrintFooListSpec( 'Alle mit A* und *e*', lFoos, lFooStartWithA.&And( lFooNameContains_e ) );

  finally
    lFoos.Free;
  end;

end;

begin
  ReportMemoryLeaksOnShutdown := True;
  try
    Test1;
  except
    on E: Exception do
      WriteLn( E.ClassName, ': ', E.Message );
  end;
  ReadLn;

end.
Für die Erfassung/Bearbeitung des Filters muss man etwas mehr ausholen.
Kaum macht man's richtig - schon funktioniert's
Zertifikat: Sir Rufo (Fingerprint: ‎ea 0a 4c 14 0d b6 3a a4 c1 c5 b9 dc 90 9d f0 e9 de 13 da 60)
  Mit Zitat antworten Zitat