AGB  ·  Datenschutz  ·  Impressum  







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

Best Practice Aggregation von Informationen

Ein Thema von alda · begonnen am 22. Feb 2015 · letzter Beitrag vom 25. Feb 2015
Antwort Antwort
alda

Registriert seit: 24. Mär 2014
Ort: Karlsruhe
93 Beiträge
 
Delphi XE6 Architect
 
#1

Best Practice Aggregation von Informationen

  Alt 22. Feb 2015, 15:01
Hallo zusammen,

ich bin gerade etwas am rumspielen und würde mir gerne Eure Meinungen und Vorschläge zu einem bestimmten Thema einholen.
Im Detail beschäftige ich mich gerade mit der Gestaltung einer Tabellenkomponente.

Vorab schonmal sorry für die Beitragslänge, ich konnte aber irgendwie auch kein Spoiler-Tag ausfindig machen um das ganze leserlicher zu gestalten ;-( Wo find ich das denn ?

Folgendes Szenario:
Eine Tabelle besteht wie gewohnt aus einem Layout von Spalte (Column), Zeile (Row) und Zelle (Cell).
Diese drei Elemente müssen je nach Vorstellung die verschiedensten Eigenschaften bereitstellen, wie z.B. Möglichkeiten zur Selektion, Lokalisierung, Sichtbarkeit und Identifizierung.

Um im weiteren Entwicklungsverlauf flexibel zu bleiben, war die Idee aus den genannten Eigenschaften je eine Schnittstelle bereitgestellt (GUIDs habe ich fürs Lesen mal weggelassen):
Delphi-Quellcode:
  ISelectable = interface(IInvokable)
    procedure Select;
    procedure Deselect;
    function IsSelected;
  end;

  ILocatable = interface(IInvokable)
    function Coordinate: TCoordinate;
  end;

  IDisplayable = interface(IInvokable)
    function IsVisible: boolean;
  end;

  IIdentifiable = interface(IInvokable)
    function UUID: String;
  end;
Wo ich mir nun absolut unschlüssig bin, ist das Bereitstellen der Eigenschaften (Selektion, Lokalisierung, Sichtbarkeit und Identifizierung) für Zeile, Spalte und Zelle - unter der Voraussetzung, dass Zeile, Spalte und Zelle InterfacedObjects bleiben. Wie würdet Ihr die Interfaces gestalten, oder was würdet Ihr komplett anders machen?:
Delphi-Quellcode:
 IRow = interface(IInvokable)
  end;

  IColumn = interface(IInvokable)
  end;

  ICell = interface(IInvokable)
  end;

1. die Interfaces der Elemente bei jeder weiteren Eigenschaft erweitern und fest verdrahten?

Interfaces:
Delphi-Quellcode:
  IRow = interface(IInvokable)
    function Selectable: ISelectable;
    function Locatable: ILocatable;
    function Displayable: IDisplayable;
    function Identifiable: IIdentifiable;
  end;

  IColumn = interface(IInvokable)
    function Selectable: ISelectable;
    function Locatable: ILocatable;
    function Displayable: IDisplayable;
    function Identifiable: IIdentifiable;
  end;

  ICell = interface(IInvokable)
    function Selectable: ISelectable;
    function Locatable: ILocatable;
    function Displayable: IDisplayable;
    function Identifiable: IIdentifiable;
  end;
Verwendung also:
Delphi-Quellcode:
....
var
  LRow: IRow;
begin
 DoThingsWithUUID( LRow.Identifiable.UUID );
end;
....

2. die Interfaces der Elemente nur Element-Spezifische Infos tragen lassen, und die allgemeinen Eigenschaften der Implementierung überlassen und casten?

Interfaces:
Delphi-Quellcode:
  IRow = interface(IInvokable)
    procedure DoThingsOnlyRowsDo;
  end;

  IColumn = interface(IInvokable)
    procedure DoThingsOnlyColumnsDo;
  end;

  ICell = interface(IInvokable)
    procedure DoThingsOnlyCellsDo;
  end;
Beispielimplementierung:
Delphi-Quellcode:
...
TRow = class(TInterfacedObject,
                        IRow,
                        IIdentifiable,
                        IDisplayable,
                        ILocatable)
...
Verwendung also:
Delphi-Quellcode:
....
var
  LRow: IRow;
begin
 DoThingsWithUUID( (LRow AS IIdentifiable).UUID );
end;
....

3. Aggregation der Informationen über eine Art Extension?

Interfaces:
Delphi-Quellcode:
  IRow = interface(IInvokable)
    procedure DoThingsOnlyRowsDo;
  end;

  IColumn = interface(IInvokable)
    procedure DoThingsOnlyColumnsDo;
  end;

  ICell = interface(IInvokable)
    procedure DoThingsOnlyCellsDo;
  end;
Beispielimplementierung:
Delphi-Quellcode:
...
TRow = class(TInterfacedObject,
                        IRow,
                        IIdentifiable,
                        IDisplayable,
                        ILocatable)
...
Extension:
Delphi-Quellcode:
  Row = record
  private
    fThis: IRow;
    function GetThis: IRow;
  public
    constructor Create(const AValue: IRow);

    class operator Implicit(const value: Row): IRow;

    function AsIdentifiable: IIdentifiable;
    function AsDisplayable: IDisplayable;
    function AsLocatable: ILocatable;
  end;

Verwendung also:
Delphi-Quellcode:
procedure DoThingsWithRow(const ARow: IRow);
var
  LRow: Row;
begin
 LRow.Create(ARow);
 DoThingsWithUUID( LRow.AsIdentifiable.UUID );
end;
....

Geändert von alda (22. Feb 2015 um 19:12 Uhr)
  Mit Zitat antworten Zitat
Benutzerbild von stahli
stahli

Registriert seit: 26. Nov 2003
Ort: Halle/Saale
4.336 Beiträge
 
Delphi 11 Alexandria
 
#2

AW: Best Practise Aggregation von Informationen

  Alt 22. Feb 2015, 15:45
Ey Alda,

ich würde in Deinem Fall überlegen, ob Dir Interfaces hier etwas bringen.

Du willst offenbar eine fixe Gitterkomponente bauen. Interfaces würden Dir ermöglichen, die aktuellen Zellen irgendwann durch andere Klassen zu ersetzen. Außerdem würden die Zellen automatisch freigegeben, wenn sie nicht mehr genutzt werden.
Bei einer Gitterkomponente würde ich erst mal denken, dass beides nicht unbedingt notwendig ist. Der Gitterkomponente können ja ruhig alle TRow, TColumn und TCell bekannt sein und sie kann die entsprechenden Objekte in eigener Kontrolle erzeugen, verwalten und freigeben.

Also Interfaces sind möglicherweise nicht wirklich hilfreich!?
(Und warum IInvokable statt IInterface?)

OK, wenn Interfaces, dann würde ich Weg 2 gehen.
Es handelt sich hier um direkte Eigenschaften der Klassen. ISelectable wird unterstützt, wenn es der Klasse zugewiesen ist. Fertig.

Im Weg 1 müsstest Du ein Objekt erzeugen und es ISelectable zuweisen. Sonst wäre es nil.
Das würde ich so anwenden, wenn man z.B. ein Auto zusammenbaut. Lenker und Motor können dann als Instanzen verwaltet werden. Auf dem Fließband ist der Motor zunächst noch nil. Erst zum Schluss wird eine Motorinstanz eingebaut.

Ich fände das für Deinen Anwendungsfall zu umständlich und unpassend.

Weg 3 würde ich ausschließen. Warum willst Du auf einmal mit Records arbeiten. (Kann sein, dass das machbar ist, aber das erscheint mir erst mal nicht ganz plausibel).
Stahli
http://www.StahliSoft.de
---
"Jetzt muss ich seh´n, dass ich kein Denkfehler mach...!?" Dittsche (2004)

Geändert von stahli (22. Feb 2015 um 15:48 Uhr)
  Mit Zitat antworten Zitat
alda

Registriert seit: 24. Mär 2014
Ort: Karlsruhe
93 Beiträge
 
Delphi XE6 Architect
 
#3

AW: Best Practise Aggregation von Informationen

  Alt 22. Feb 2015, 16:28
Du willst offenbar eine fixe Gitterkomponente bauen. Interfaces würden Dir ermöglichen, die aktuellen Zellen irgendwann durch andere Klassen zu ersetzen. Außerdem würden die Zellen automatisch freigegeben, wenn sie nicht mehr genutzt werden.
Bei einer Gitterkomponente würde ich erst mal denken, dass beides nicht unbedingt notwendig ist. Der Gitterkomponente können ja ruhig alle TRow, TColumn und TCell bekannt sein und sie kann die entsprechenden Objekte in eigener Kontrolle erzeugen, verwalten und freigeben.
Das würde bedeuten, dass jemand Drittes keine Möglichkeit hätte die Default-Implementierungen von Spalte, Zeile und Zelle zu tauschen, außer er leitet von den Defaultklassen ab - und das bedeutet er muss das Verhalten ändern / überschreiben.

(Und warum IInvokable statt IInterface?)
Für Interception (Mocks), dann spar ich mir das $M+.

OK, wenn Interfaces, dann würde ich Weg 2 gehen.
Es handelt sich hier um direkte Eigenschaften der Klassen. ISelectable wird unterstützt, wenn es der Klasse zugewiesen ist. Fertig.
Genau da bin ich mir unschlüssig. So ist für jemand Dritten nicht sofort klar welche Interfaces z.B. eine Zellenimplementierung unterstützen muss um reibungslos in der Tabellenkomponente zu funktionieren (ein Cast schlägt z.B. fehl). Also angenommen er würde die Implementierung hinter ICell austauschen wollen. Oder nicht?

Im Weg 1 müsstest Du ein Objekt erzeugen und es ISelectable zuweisen. Sonst wäre es nil.
Das würde ich so anwenden, wenn man z.B. ein Auto zusammenbaut. Lenker und Motor können dann als Instanzen verwaltet werden. Auf dem Fließband ist der Motor zunächst noch nil. Erst zum Schluss wird eine Motorinstanz eingebaut.
Die Implementierung setzt natürlich voraus, dass die Eigenschaften niemals NIL sind.

Weg 3 würde ich ausschließen. Warum willst Du auf einmal mit Records arbeiten. (Kann sein, dass das machbar ist, aber das erscheint mir erst mal nicht ganz plausibel).
Die Idee war, in der Tabellenkomponente immer über Records auf die Instanzen von Row, Cell und Column zuzugreifen und dort alle untersützten Interfaces zu konsolidieren. Aber das gefällt mir auch nicht, da stimme ich Dir zu

Geändert von alda (22. Feb 2015 um 18:11 Uhr)
  Mit Zitat antworten Zitat
Benutzerbild von BUG
BUG

Registriert seit: 4. Dez 2003
Ort: Cottbus
2.094 Beiträge
 
#4

AW: Best Practice Aggregation von Informationen

  Alt 23. Feb 2015, 00:29
Dein Problem resultiert ein bisschen daraus, dass Delphi/COM-Interfaces keine Mehrfachvererbung unterstützen. Ansonsten könntest du dir einfach ein "Bündel" von zu unterstützenden Interfaces schnüren. (siehe auch)
Von deinen Lösungen ist Lösung 1 an dieser Sichtweise nächsten dran.

Eine andere Variante wäre es, eine abstrakte Basisklasse zu erstellen, die alle nötigen Interfaces besitzt. Wenn jemand unbedingt eine andere Basis braucht, muss er halt einen Adapter schreiben.
  Mit Zitat antworten Zitat
alda

Registriert seit: 24. Mär 2014
Ort: Karlsruhe
93 Beiträge
 
Delphi XE6 Architect
 
#5

AW: Best Practice Aggregation von Informationen

  Alt 25. Feb 2015, 09:04
Dein Problem resultiert ein bisschen daraus, dass Delphi/COM-Interfaces keine Mehrfachvererbung unterstützen. Ansonsten könntest du dir einfach ein "Bündel" von zu unterstützenden Interfaces schnüren. (siehe auch)
Von deinen Lösungen ist Lösung 1 an dieser Sichtweise nächsten dran.

Eine andere Variante wäre es, eine abstrakte Basisklasse zu erstellen, die alle nötigen Interfaces besitzt. Wenn jemand unbedingt eine andere Basis braucht, muss er halt einen Adapter schreiben.
Ich werd auch erstmal mit Variante 1 starten denk ich, da diese Infos essentiell sind und einem viele Supports() Aufrufe ersparen. Weitere Meinungen sind aber trotzdem gerne Willkommen
  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 02:36 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