Einzelnen Beitrag anzeigen

Benutzerbild von Sir Rufo
Sir Rufo

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

AW: class helper generic class

  Alt 8. Dez 2014, 07:51
Du musst ja auch nicht vererben, sondern du kannst ja auch wrappen.

Diese verlinkte Lib habe ich mir mal angesehen und mal kurz was zusammengefasst
Delphi-Quellcode:
unit GenericGraph.Global;

interface

uses
  SysUtils,
  Generics.Collections,
  GenericGraph.ColorSchemes,
  Variants;

type
{$REGION 'Documentation'}
  /// <summary>
  /// Definition for a marker, used for edges, vertices and graphs
  /// </summary>
{$ENDREGION}
  TMarker = Variant;

{$REGION 'Documentation'}
  /// <summary>
  /// An associative List of Markers
  /// </summary>
{$ENDREGION}
  TMarkerList = TDictionary<string, TMarker>;

  TCore = class
    Marker: TMarkerList;
{$REGION 'Documentation'}
    /// <summary>
    /// The degree is used in an undirected graph and determined the amount
    /// of direct neighbours to a vertex
    /// </summary>
{$ENDREGION}
    Degree: Integer;
    function HasAdditionalAttributes: Boolean; virtual;
    destructor Destroy; override;
    procedure Mark( Key: String; Value: TMarker );
    function GetMark( Key: String ): TMarker;
    function HasMark( Key: String ): Boolean;
    procedure UnMark( Key: String );
    function HasAnyMark( ): Boolean;
    procedure ClearMarks( );
  end;

  TCore<T> = class( TCore )
    Data: T;
  end;

{$REGION 'Documentation'}
  /// <summary>
  /// Contains attributes to customize the output of a TVertex
  /// </summary>
{$ENDREGION}

  TVertexOutputAttributes = record
    Caption: String;
    Shape: String;
    Color: TGraphVizColor;
    FontColor: TGraphVizColor;
    FillColor: String;
    FontSize: Integer;
    FontName: String;
    ReverseDirection: Boolean;
  end;

{$REGION 'Documentation'}
  /// <summary>
  /// Represents a single vertex in the graph
  /// </summary>
{$ENDREGION}

  TVertex<T> = class( TCore<T> )
  public
    Name: String;
    OutputAttributes: TVertexOutputAttributes;

{$REGION 'Documentation'}
    /// <summary>
    /// The in-degree is used in an directed graph and determines the amount
    /// of edges entering a vertex
    /// </summary>
{$ENDREGION}
    DegreeIn: Integer;

{$REGION 'Documentation'}
    /// <summary>
    /// The out-degree is used in an directed graph and determines the amount
    /// of edges�leaving a vertex
    /// </summary>
{$ENDREGION}
    DegreeOut: Integer;
    function HasAdditionalAttributes: Boolean; override;
  end;

{$REGION 'Documentation'}
  /// <summary>
  /// A simple ordered list of vertices
  /// </summary>
{$ENDREGION}

  TVertexList<T> = class( TList < TVertex < T >> );

{$REGION 'Documentation'}
  /// <summary>
  /// Contains attributes to customize the output of a TEdge
  /// </summary>
{$ENDREGION}

  TEdgeOutputOptions = record
    Caption: String;
    Color: String;
    Style: String;
  end;

{$REGION 'Documentation'}
  /// <summary>
  /// Represents a single edge in the graph
  /// First attribute is the data assigned to the edge
  /// Second attribute is the data assigned to the vertex (should match your implementation of TVertex<V>)
  /// </summary>
{$ENDREGION}

  TEdge<T, V> = class( TCore<T> )
    VertexA: TVertex<V>;
    VertexB: TVertex<V>;
    Directed: Boolean;
    Degree_Reverse: Integer;
    Weight: Integer;
    OutputAttributes: TEdgeOutputOptions;

    constructor Create( pDirected: Boolean );

    function HasAdditionalAttributes( ): Boolean; override;
  end;

  TEdgeList<T, V> = class( TList < TEdge < T, V >> );

  TGraphOutputOptions = record
    NodeSep: Double;
    RenderAsNonDirectedGraph: Boolean;

    // Added by mc.botha
    TrueColor, Splines, Overlap: Boolean;
    BGColor: TGraphVizColor;
  end;

  EBasicGraphException = Exception;
  EDuplicateEdge = class( EBasicGraphException );

implementation

{ TCore }

procedure TCore.ClearMarks;
begin
  FreeAndNil( Marker );
end;

destructor TCore.Destroy;
begin
  FreeAndNil( Marker );
  inherited;
end;

function TCore.GetMark( Key: String ): TMarker;
begin
  Result := Null;
  if Assigned( Marker )
  then
    begin
      if Marker.ContainsKey( Key )
      then
        Result := Marker.Items[Key];
    end;
end;

function TCore.HasAdditionalAttributes: Boolean;
begin
  Result := False;
end;

function TCore.HasAnyMark: Boolean;
begin
  Result := False;
  if Assigned( Marker )
  then
    Result := Marker.Count > 0;
end;

function TCore.HasMark( Key: String ): Boolean;
begin
  Result := False;
  if Assigned( Marker )
  then
    Result := Marker.ContainsKey( Key );
end;

procedure TCore.Mark( Key: String; Value: TMarker );
begin
  if not Assigned( Marker )
  then
    Marker := TMarkerList.Create;

  if Marker.ContainsKey( Key )
  then
    Marker.Items[Key] := Value
  else
    Marker.Add( Key, Value );
end;

procedure TCore.UnMark( Key: String );
begin
  Assert( Assigned( Marker ) );

  if Marker.ContainsKey( Key )
  then
    Marker.Remove( Key );

  if Marker.Count = 0
  then
    FreeAndNil( Marker );
end;

{ TVertex<T> }

function TVertex<T>.HasAdditionalAttributes: Boolean;
begin
  Result := ( Trim( OutputAttributes.Shape ) <> '' ) or ( Trim( OutputAttributes.Caption ) <> '' ) or ( Trim( OutputAttributes.Color ) <> '' ) or
    ( Trim( OutputAttributes.FontColor ) <> '' ) or ( OutputAttributes.FontSize <> 0 ) or ( OutputAttributes.ReverseDirection ) or
    ( Trim( OutputAttributes.FontName ) <> '' );
end;

{ TEdge<T, V> }

constructor TEdge<T, V>.Create( pDirected: Boolean );
begin
  inherited Create;
  Directed := pDirected;
  Weight := 1;
end;

function TEdge<T, V>.HasAdditionalAttributes: Boolean;
begin
  Result := ( Trim( OutputAttributes.Caption ) <> '' ) or ( Trim( OutputAttributes.Color ) <> '' ) or ( Trim( OutputAttributes.Style ) <> '' );
end;

end.
Wenn du jetzt eine andere Funktionalität brauchst, dann baue dir einen Wrapper, der arbeitet dann auch nicht anders als ein class helper.
Delphi-Quellcode:
TAbstractWrapper = class
end;

TCoreWrapper = class( TAbstractWrapper )
  constructor Create( AInstance : TCore );
end;

TCoreWrapper<T> = class( TCoreWrapper )
  constructor Create( AInstance : TCore<T>;
end;

TVertexWrapper<T> = class( TCoreWrapper<T> )
  constructor Create( AInstance : TVertex<T> );
end;

TEdgeWrapper<T,V> = class( TCoreWrapper<T> )
  constructor Create( AInstance : TEdge<T,V> );
end;
So kannst deine Funktionalitäten ziemlich DRY implementieren.
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