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.123 Beiträge
 
Delphi 11 Alexandria
 
#1

class helper generic class

  Alt 7. Dez 2014, 20:49
unter http://stackoverflow.com/questions/1...-generic-class wird als Einschränkung "keine class helper " für generische Datentypen genannt.

Dh. ich kann keine Unit aufbauen

Delphi-Quellcode:
unit GraphGenericHelperTypes;

interface

uses MygenericGraphTypes;


type TVertexhelper<T>= class helper for TVertex<T>
    
     OutputAttributes: TVertexOutputAttributes;
    
     function HasAdditionalAttributes: Boolean
end;

implementation


end.

um einen Datentyp TVertex<T> wie in http://sourceforge.net/projects/gengraph/files/ abzuwandeln.


ich möchte alle Funktionalität der Klassen TVertex<T> = class, TEdge<T, V> = class, ....
in einen Bestandteil der nur für die Graph-Mathematik nötig ist und einen Bestandteil der für die Visualisierung
via GraphViz (http://www.graphviz.org/) nötig ist auftrennen. Wenn immer sich das Tool zur Graph-Visualisierung ändert soll der Core Bestandteil der Graph-Klasse unverändert bestehen bleiben.

Gibt es eine alternative Lösung für dieses Problem in Delphi ?

Geändert von bernhard_LA ( 7. Dez 2014 um 20:53 Uhr)
  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 7. Dez 2014, 20:58
Du hast also sowas wie ein
Delphi-Quellcode:
TCoreVertex<T> = class
  procedure Foo;
end;
und so ein Visualisierungsgedöns
Delphi-Quellcode:
TVertex<T> = class( TCoreVertex<T> )
  procedure Bar;
end;
?
Oder wie muss ich das verstehen?
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
Benutzerbild von himitsu
himitsu

Registriert seit: 11. Okt 2003
Ort: Elbflorenz
43.142 Beiträge
 
Delphi 12 Athens
 
#3

AW: class helper generic class

  Alt 7. Dez 2014, 22:25
Es gibt halt keine generischen Class-Helper.
Genauso, wie man keine generischen Prozeduren deklarieren kann.

Man kann maximal einen ungenerischen Class-Helper für einen Generic definieren.
Garbage Collector ... Delphianer erzeugen keinen Müll, also brauchen sie auch keinen Müllsucher.
my Delphi wish list : BugReports/FeatureRequests
  Mit Zitat antworten Zitat
bernhard_LA

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

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
 
#5

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
 
#6

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 16:21 Uhr.
Powered by vBulletin® Copyright ©2000 - 2024, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024 by Thomas Breitkreuz