AGB  ·  Datenschutz  ·  Impressum  







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

Austausch von Funktionalität , Interfaces ?

Ein Thema von bernhard_LA · begonnen am 21. Jan 2017 · letzter Beitrag vom 24. Jan 2017
Antwort Antwort
bernhard_LA

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

Austausch von Funktionalität , Interfaces ?

  Alt 21. Jan 2017, 16:40
Ich habe einen Satz von ca. 20 Funktionen in diversen Projekten verwendet. So weit Ok. Nun möchte ich den Code in diesen Projekten nicht anfassen, auch die Funktionsnamen nicht. Allerdings soll durch eine Variable zukünfig gesteuert werden ob der alte Code oder neue Funtionen (selbe Funktionsnamen) aber andere Funktionalität augeführt wird.

aktuelle Idee : alles über Interfaces zu steuern

Delphi-Quellcode:
 unit Unit_interface;

interface

uses classes, types;
type
     IRegistryAccess = interface
     ['{257E3C2E-3601-4FB3-B57C-A7E671EC1B7E}']
       // eine Funktion, gleicher Name aber verschiedene Funktionalitäten
       function ReadInteger (IntegerName : Integer) : Integer ;
     end;

type TRegistryReader = class (TInterfacedObject, IRegistryAccess)
     function ReadInteger (IntegerName : Integer) : Integer ;
end;

type TRegistryFileReader = class (TInterfacedObject, IRegistryAccess)
     function ReadInteger (IntegerName : Integer) : Integer ;
end;

implementation

{ TRegistryReader }

function TRegistryReader.ReadInteger(IntegerName: Integer): Integer;
begin
     Result := -1 ; // test , gebe -1 zurück
end;

{ TRegistryFileReader }

function TRegistryFileReader.ReadInteger(IntegerName: Integer): Integer;
begin
    Result := 333 ; // und hier gebe einen anderen Wert zurück
end;

end.

und hier der Aufruf :


Delphi-Quellcode:
unit UnitMain;

interface

uses
  Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants,
  System.Classes, Vcl.Graphics,
  Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.StdCtrls, Unit_interface;

type
  TForm1 = class(TForm)
    btn_GO: TButton;
    CheckBox1: TCheckBox;
    Memo1: TMemo;
    CheckBox2: TCheckBox;
    procedure btn_GOClick(Sender: TObject);
  private
    { Private-Deklarationen }
  public
    { Public-Deklarationen }
    Myregistry: IRegistryAccess;
  end;

var
  Form1: TForm1;

implementation

{$R *.dfm}

procedure TForm1.btn_GOClick(Sender: TObject);
begin
     if CheckBox2.Checked then
  begin
    Myregistry := TRegistryReader.Create;
  end
  else
  begin
    Myregistry := TRegistryFileReader.Create;
  end;

   memo1.lines.add ( IntToStr( Myregistry.ReadInteger(1 )));
end;

end.

Gibt es einen besseren Ansatz für diese Aufgabe ?

Geändert von bernhard_LA (21. Jan 2017 um 16:57 Uhr)
  Mit Zitat antworten Zitat
Fritzew

Registriert seit: 18. Nov 2015
Ort: Kehl
678 Beiträge
 
Delphi 11 Alexandria
 
#2

AW: Austausch von Funktionalität , Interfaces ?

  Alt 21. Jan 2017, 18:15
Also ich denke Du bist auf dem richtigen Weg.
schau Dir auf jeden Fall mal an was https://bitbucket.org/sglienke/spring4d
Dir zu diesem Thema bietet. Für mich ist das eine der besten Bibliotheken rund um Delphi.
An dieser Stelle noch mal: Danke Stevie!!!!!
Fritz Westermann
  Mit Zitat antworten Zitat
bernhard_LA

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

AW: Austausch von Funktionalität , Interfaces ?

  Alt 21. Jan 2017, 23:23
ich möchte die Myregistry: IRegistryAccess; nicht in meinen Mainform haben, geht dies technisch ?
Meine aktuelle Code Version funktioniert nicht mehr, ich müsste den Wert der Boolschen Variable in der initialization jeweils Berücksichtigen und neu Anpassen. Die erste Version oben hatte korrekt funktioniert.



Delphi-Quellcode:
type
  TForm1 = class(TForm)
    btn_GO: TButton;
    CheckBox1: TCheckBox;
    Memo1: TMemo;
    CheckBox2: TCheckBox;
    procedure btn_GOClick(Sender: TObject);
    procedure CheckBox2Click(Sender: TObject);
  private
    { Private-Deklarationen }
  public
    { Public-Deklarationen }

  end;

var
  Form1: TForm1;


implementation

{$R *.dfm}

procedure TForm1.btn_GOClick(Sender: TObject);
begin

  /// ich will die Klasse nicht im Hauptprogramm haben !
  Memo1.lines.add(IntToStr(Myregistry.ReadInteger(1)));


  /// Zielversion -> im code sieht man nicht mehr welche implementierung
  /// ausgerufen wird
  Memo1.lines.add(IntToStr(ReadInteger(1)));
end;

procedure TForm1.CheckBox2Click(Sender: TObject);
begin
     useregistryClass := CheckBox2.Checked;
end;

end
.



Delphi-Quellcode:
unit Unit_interface;

interface

uses classes, types;

type
  IRegistryAccess = interface
    ['{257E3C2E-3601-4FB3-B57C-A7E671EC1B7E}']
    function ReadInteger(IntegerName: Integer): Integer;
  end;

type
  TRegistryReader = class(TInterfacedObject, IRegistryAccess)
    function ReadInteger(IntegerName: Integer): Integer;
  end;

type
  TRegistryFileReader = class(TInterfacedObject, IRegistryAccess)
    function ReadInteger(IntegerName: Integer): Integer;
  end;

var
  Myregistry: IRegistryAccess;
  useregistryClass: Boolean;

function ReadInteger(index: Integer): Integer;

implementation

function ReadInteger(index: Integer): Integer;
begin
  Result := Myregistry.ReadInteger(1);
end;

{ TRegistryReader }

function TRegistryReader.ReadInteger(IntegerName: Integer): Integer;
begin
  Result := -1;
end;

{ TRegistryFileReader }

function TRegistryFileReader.ReadInteger(IntegerName: Integer): Integer;
begin
  Result := 333;
end;

initialization

begin
  if useregistryClass then
  begin
    Myregistry := TRegistryReader.Create;
  end
  else
  begin
    Myregistry := TRegistryFileReader.Create;
  end;
end;

end.
  Mit Zitat antworten Zitat
Benutzerbild von DeddyH
DeddyH

Registriert seit: 17. Sep 2006
Ort: Barchfeld
27.624 Beiträge
 
Delphi 12 Athens
 
#4

AW: Austausch von Funktionalität , Interfaces ?

  Alt 22. Jan 2017, 10:34
Das zu benutzende Interface muss Dein Hauptformular schon kennen, wie soll es dieses auch sonst verwenden? Was es hingegen nicht kennen muss, ist die konkrete Klasse dahinter. Um wirklich flexibel zu sein bräuchtest Du aber eine ClassFactory, und das ist einiger Aufwand, wenn es denn zuverlässig funktionieren soll (ich hab das alles schon hinter mir). Willst Du diesen Aufwand nicht selber treiben, solltest Du Dir wirklich das weiter oben empfohlene Spring4D einmal anschauen, wenn ich mich recht erinnere ist da eine Projektgruppe als Demo dabei, wo die einzelnen Schritte exakt beschrieben und nachvollzogen werden.
Detlef
"Ich habe Angst vor dem Tag, an dem die Technologie unsere menschlichen Interaktionen übertrumpft. Die Welt wird eine Generation von Idioten bekommen." (Albert Einstein)
Dieser Tag ist längst gekommen
  Mit Zitat antworten Zitat
bernhard_LA

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

AW: Austausch von Funktionalität , Interfaces ?

  Alt 22. Jan 2017, 13:05
aktuell würde der Code wieder machen was er soll :
Delphi-Quellcode:
  TForm1 = class(TForm)
    btn_GO: TButton;
    CheckBox1: TCheckBox;
    Memo1: TMemo;
    CheckBox2: TCheckBox;
    procedure btn_GOClick(Sender: TObject);
    procedure CheckBox2Click(Sender: TObject);
  private
    { Private-Deklarationen }
  public
    { Public-Deklarationen }

  end;

var
  Form1: TForm1;


implementation

{$R *.dfm}

procedure TForm1.btn_GOClick(Sender: TObject);
begin

  /// ich will die Klasse nicht im Hauptprogramm haben !
  /// wäre nicht nötig
  Memo1.lines.add(IntToStr(Myregistry.ReadInteger(1)));


  /// Zielversion -> im code sieht man nicht mehr welche implementierung
  /// ausgerufen wird
  Memo1.lines.add(IntToStr(ReadInteger(1)));
end;

procedure TForm1.CheckBox2Click(Sender: TObject);
begin
     useregistryClass := CheckBox2.Checked;

     InitReader;
end;

end.
und die Ausgelagerte Klasse

Delphi-Quellcode:
unit Unit_interface;

interface

uses classes, types;

type
  IRegistryAccess = interface
    ['{257E3C2E-3601-4FB3-B57C-A7E671EC1B7E}']
    function ReadInteger(IntegerName: Integer): Integer;
  end;

type
  TRegistryReader = class(TInterfacedObject, IRegistryAccess)
    function ReadInteger(IntegerName: Integer): Integer;
  end;

type
  TRegistryFileReader = class(TInterfacedObject, IRegistryAccess)
    function ReadInteger(IntegerName: Integer): Integer;
  end;

var
  Myregistry: IRegistryAccess;
  useregistryClass: Boolean;

function ReadInteger(index: Integer): Integer;
function InitReader : Boolean ;
function FreeReader : Boolean;

implementation

function ReadInteger(index: Integer): Integer;
begin
  Result := Myregistry.ReadInteger(1);
end;

{ TRegistryReader }

function TRegistryReader.ReadInteger(IntegerName: Integer): Integer;
begin
  Result := -1;
end;

{ TRegistryFileReader }

function TRegistryFileReader.ReadInteger(IntegerName: Integer): Integer;
begin
  Result := 333;
end;

function InitReader : Boolean ;
begin
  if useregistryClass then
  begin
    Myregistry := TRegistryReader.Create;
  end
  else
  begin
    Myregistry := TRegistryFileReader.Create;
  end;
end;


function FreeReader : Boolean;
begin
   // Myregistry.Free;
end;

meine Frage hierzu : laufe ich jetzt in weitere unbekannte Probleme, ist mein Ansatz so Ok?
Die bisherigen Funktionen zum Lesen aus der Registry werden als Wrapper einer Klasse definiert.
Welche Klasse verwendet wird definiere ich über eine Init Funktion in meiner unit.
Der bisherige Code wandert in die Klasse , der neue Code entsteht in der weiteren neu zu implementierenden Klasse "TRegistryFileReader" .
Was ist der Vorteil einer ClassFactory

Geändert von bernhard_LA (22. Jan 2017 um 13:18 Uhr)
  Mit Zitat antworten Zitat
Benutzerbild von DeddyH
DeddyH

Registriert seit: 17. Sep 2006
Ort: Barchfeld
27.624 Beiträge
 
Delphi 12 Athens
 
#6

AW: Austausch von Funktionalität , Interfaces ?

  Alt 22. Jan 2017, 14:05
Ein Minimalbeispiel (die "Factory" hier ist sehr simpel und unflexibel, soll aber auch nur das Prinzip verdeutlichen). Nehmen wir folgendes sehr simple Interface:
Delphi-Quellcode:
unit TierIntf;

interface

type
  ITier = interface
    ['{443BCADC-CD02-4A2A-BB55-A9AEBE03D37D}']
    procedure GibLaut;
  end;

implementation

end.
Jetzt bauen wir uns 2 Klassen, die das Interface implementieren (der Einfachheit halber in derselben Unit):
Delphi-Quellcode:
unit TierClasses;

interface

uses
  Dialogs, TierIntf;

type
  THund = class(TInterfacedObject, ITier)
  public
    procedure GibLaut;
  end;

  TKatze = class(TInterfacedObject, ITier)
  public
    procedure GibLaut;
  end;

implementation

{ THund }

procedure THund.GibLaut;
begin
  ShowMessage('Wuff');
end;

{ TKatze }

procedure TKatze.GibLaut;
begin
  ShowMessage('Miau');
end;

end.
Nun eine Klassenfabrik (einen Singleton), die uns je nach Bedingung die eine oder andere Klasse instanziert.
Delphi-Quellcode:
unit TierFactory;

interface

uses
  TierIntf, TierClasses;

type
  TTierFactory = class abstract
  public
    class function GetTier(IstHund: Boolean): ITier; static;
  end;

implementation

{ TTierFactory }

class function TTierFactory.GetTier(IstHund: Boolean): ITier;
begin
  if IstHund then
    Result := THund.Create
  else
    Result := TKatze.Create;
end;

end.
Das Frontend muss dann letztendlich nur noch das Interface und die Fabrik kennen.
Delphi-Quellcode:
procedure TFormTest.ButtonTierClick(Sender: TObject);
var
  Tier: ITier;
begin
  Tier := TTierFactory.GetTier(cbHund.Checked);
  Tier.GibLaut;
end;
Um wirklich flexibel zu werden, wäre die Bedingung aber kein Boolean, sondern ein Datentyp mit nahezu unendlich vielen möglichen Werten, z.B. ein String. Die Factory würde dann mindestens über 2 Klassenmethoden verfügen: Registrierung einer Klasse mit einem der möglichen Werte und Rückgabe einer Instanz anhand eines registrierten Wertes (oder auch nil, wenn kein registrierter Wert vorhanden). Um das Programm um weitere Tiere zu erweitern müssten sich deren Klassen lediglich an der Factory registrieren, an der Factory selbst und erst recht am Frontend sind keine Änderungen nötig.

[edit] Nachtrag: Bei der zuletzt angegebenen Vorgehensweise entfällt dann auch die Notwendigkeit, die Klassenunits in die uses-Klausel der Factory aufnehmen zu müssen. Allerdings ist das Instanzieren der entsprechenden Klasse dann nicht ganz trivial, ich habe das damals mit einer Menge RTTI realisieren müssen. [/edit]
Detlef
"Ich habe Angst vor dem Tag, an dem die Technologie unsere menschlichen Interaktionen übertrumpft. Die Welt wird eine Generation von Idioten bekommen." (Albert Einstein)
Dieser Tag ist längst gekommen

Geändert von DeddyH (22. Jan 2017 um 14:13 Uhr)
  Mit Zitat antworten Zitat
bernhard_LA

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

AW: Austausch von Funktionalität , Interfaces ?

  Alt 22. Jan 2017, 14:30
Danke für das Beispiel
  Mit Zitat antworten Zitat
freimatz

Registriert seit: 20. Mai 2010
1.443 Beiträge
 
Delphi 11 Alexandria
 
#8

AW: Austausch von Funktionalität , Interfaces ?

  Alt 24. Jan 2017, 17:28
... Um wirklich flexibel zu sein bräuchtest Du aber eine ClassFactory, und das ist einiger Aufwand, wenn es denn zuverlässig funktionieren soll (ich hab das alles schon hinter mir). Willst Du diesen Aufwand nicht selber treiben, solltest Du Dir wirklich das weiter oben empfohlene Spring4D einmal anschauen, wenn ich mich recht erinnere ist da eine Projektgruppe als Demo dabei, wo die einzelnen Schritte exakt beschrieben und nachvollzogen werden.
Einspuch
Solange er die Grundlagen nicht verstanden hat sollte er sich nicht mit Spring4D beschäftigen. Lieber macht er selber mal eine kleine Factory bis das mal läuft. Bis dahin finde ich Spring4D recht abschreckend.
  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 15:48 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