AGB  ·  Datenschutz  ·  Impressum  







Anmelden
Nützliche Links
Registrieren
Thema durchsuchen
Ansicht
Themen-Optionen

class helper generic class

Ein Thema von bernhard_LA · begonnen am 7. Dez 2014 · letzter Beitrag vom 8. Dez 2014
Antwort Antwort
bernhard_LA

Registriert seit: 8. Jun 2009
Ort: Bayern
1.138 Beiträge
 
Delphi 11 Alexandria
 
#1

AW: class helper generic class

  Alt 7. Dez 2014, 23:01
der Plan geht wie folgt :

eine Klasse für TVertex nur mit Eigenschaften die eine Vertex auch hat....
Delphi-Quellcode:
  TVertex<T> = class
    public
    /// alles was hier kommt brauche ich für die Graph Mathematik
    ...
    ...
    end;
und dann gibt es noch


Delphi-Quellcode:
  TVertexhelper<T> = class helper for TVertex<T>
    public
    /// alles was hier kommt brauche ich *** nur **** für die Visualisierung
    ...
    ...
    end;


alle Rechenoperationen laufen auf den Basis Klassen TVertex<T>; Wer was zeichnen lassen wir füllt bei Bedarf die Classhelper felder auf.

Vererben will ich nicht weil dann alle Algorithmen auch eine Ableitung von TVertex<T> erwarten und dies ist eigentlich unlogisch.
  Mit Zitat antworten Zitat
Benutzerbild von Sir Rufo
Sir Rufo

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

AW: class helper generic class

  Alt 8. Dez 2014, 06: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
Dejan Vu
(Gast)

n/a Beiträge
 
#3

AW: class helper generic class

  Alt 8. Dez 2014, 07:08
alle Rechenoperationen laufen auf den Basis Klassen TVertex<T>; Wer was zeichnen lassen wir füllt bei Bedarf die Classhelper felder auf.
Hmm.. Im Endeffekt sind dann alle Operationen auf TVertex<T> definiert, was die Klasse ziemlich überladen erscheint. Du klatschtst zwar Funktionalität über Class Helper ran, aber im Endeffekt schmeißt Du doch alles in einen (TVertex<T>-)Topf.

Ich würde doch einfach separate Berechnungsklassen schreiben. Damit bist Du im Endeffekt doch besser dran (finde ich). So eine Klasse kann ja auch statisch sein, sodaß die Instantiierung wegfällt.

Bei der Verwenden sieht man dann aber auch genau, wo die Implementierung der Berechnung steht:

Procedure

Delphi-Quellcode:
  myVertex.DoSomeWeirdAndMagicStuff(someOtherVertix);
// vs.
  TTheSpecialCalculator.DoSomeWeirdAndMagicStuff(myVertex, someOtherVertix);
  Mit Zitat antworten Zitat
Antwort Antwort


Forumregeln

Es ist dir nicht erlaubt, neue Themen zu verfassen.
Es ist dir nicht erlaubt, auf Beiträge zu antworten.
Es ist dir nicht erlaubt, Anhänge hochzuladen.
Es ist dir nicht erlaubt, deine Beiträge zu bearbeiten.

BB-Code ist an.
Smileys sind an.
[IMG] Code ist an.
HTML-Code ist aus.
Trackbacks are an
Pingbacks are an
Refbacks are aus

Gehe zu:

Impressum · AGB · Datenschutz · Nach oben
Alle Zeitangaben in WEZ +1. Es ist jetzt 01:37 Uhr.
Powered by vBulletin® Copyright ©2000 - 2025, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024-2025 by Thomas Breitkreuz