AGB  ·  Datenschutz  ·  Impressum  







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

Interface richtig umgesetzt?

Ein Thema von TheMiller · begonnen am 23. Dez 2014 · letzter Beitrag vom 5. Jan 2015
Antwort Antwort
alda

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

AW: Interface richtig umgesetzt?

  Alt 23. Dez 2014, 13:52
@mjustin: Mache ich mir da nicht die Flexibilität kaputt, die ich durch das Interface erreichen wollte?
Das ist der Sinn eines Interfaces - ich kann beliebige Implementierungen (Klassen) austauschen. Dein Ansatz das innerhalb des Konstruktors
zu machen ist unschön und nimmt dir die Flexibilität, da Du diese Klasse nun doch an die Implementierung (TActiveMQ.Create) koppelst, obwohl Du ein Interfaces dafür hast (IMy_MQ). Der korrekte Ansatz wäre hier, wenn überhaupt, eine fertige MessageQueue mit in den Konstruktiv zu übergeben (IMY_MQ) und somit diese Klasse von der Implementierung von IMy_MQ zu entkoppeln.

In meinem Beispiel müsste ich bei einem Brokerwechsel nur eine Zeile für die gesamte Anwendung ändern. Bei deiner Lösung müsste ich ein komplette Objekte tauschen. Warum nutzt du in diesem Fall ein Interface?
In seinem Beispiel wäre es genau so, nur dass die "Zeile" von der Du redest nicht innerhalb einer MQ-Klasse ist, sondern außerhalb von einer Factory oder sonstwem übernommen wird.

Um das Beispiel von mjustin zu vollenden, hättest Du z.B. noch einen TMessageQueueProvider (oder wie auch immer man das nennen möchte:
Delphi-Quellcode:
IMessageQueueProvider = interface
....
   function CreateMessageQueue(const AMessageBrokerType: TMessageBrokerType): IMessageBrokerClient;
end;

TMessageQueueProvider = class(TInterfacedObject, IMessageQueueProvider)
public
   function CreateMessageQueue(const AMessageBrokerType: TMessageBrokerType): IMessageBrokerClient;
end;

....

implementation

function TMessageQueueProvider .CreateMessageQueue(const AMessageBrokerType: TMessageBrokerType): IMessageBrokerClient;
begin
   case AMessageBrokerType:
      mqMS:
         Result := TMy_MSMQ.Create;
      msAtiveMQ:
         Result := TActiveMQ.Create;
      else
         raise EMessageQueueBrokerNotSupportedError.Create('');
end;
....

Geändert von alda (23. Dez 2014 um 14:02 Uhr)
  Mit Zitat antworten Zitat
mjustin

Registriert seit: 14. Apr 2008
3.011 Beiträge
 
Delphi 2009 Professional
 
#2

AW: Interface richtig umgesetzt?

  Alt 23. Dez 2014, 14:19
Delphi-Quellcode:
   case AMessageBrokerType:
      mqMS:
         Result := TMy_MSMQ.Create;
      msAtiveMQ:
         Result := TActiveMQ.Create;
      else
         raise EMessageQueueBrokerNotSupportedError.Create('');
In einem Edit meines Beitrags habe ich angemerkt, dass diese Flexibilität auch einen Preis, nämlich eine entsprechend größere Anwendungsdatei hat, da auch die Implementierungs-Klassen für alle unbenutzten Message Broker eingebunden werden.
(Man könnte aber durch Einsatz von IFDEF verschiedene Versionen der Anwendung erstellen, die je nach Bedarf nur einen Message Broker oder eine Auswahl (zwei bis N) unterstützen.)
Michael Justin
  Mit Zitat antworten Zitat
Dejan Vu
(Gast)

n/a Beiträge
 
#3

AW: Interface richtig umgesetzt?

  Alt 23. Dez 2014, 14:31
Wie willst Du mit diesem Interface eigentlich einen TCP-Client umsetzen?

Du musst anders herum anfangen: Beschreibe die Funktionalität und die Methoden, die Du für die Kommunikation benötigst, ohne die Begriffe TCP, UDP, MSMQ, Schnur, RS-232 und Buschtrommel zu verwenden.

Also: Mein Client soll sich immer nur mit einem konkreten Server unterhalten. Dafür brauche ich eine 'Connect' (muss die wirklich Connect heißen) Routine. Oder besser (und allgemeiner) : StartConnection.

Dann will ich dem eine Nachricht als String schicken können (SendMessage).
Dann will ich noch eine Anfrage schicken und auf das Ergebnis (auch ein String) warten. Aber nur maximal X Sekunden. (QueryResponse)

Und zu guter Letzt möchte ich noch, das der Client wieder offen für einen anderen Server ist (StopConnection)

Fertig ist das allgemeine Client-Interface
Delphi-Quellcode:
Type
  IClientConnection = Interface
    procedure StartConnection (server : IServer);
    procedure SendMessage (message : String);
    procedure QueryResponse (query : String; var response : String; timeout : Integer);
    procedure StopConnection;
  end;
Fertig ist das Interface. Für die Nachrichten könntest Du nun auch noch ein allgemeines Interface bauen, aber so geht es erst einmal. Natürlich fehlt noch z.B. die Stream-Funktion, aber das kannst Du ja später machen.

Schreibe nun eine konkrete TMSMQClientConnection-Klasse, die das IClientConnection-Interface implementiert.
Danach schreibst Du noch ein TTCPClientConnection-Klasse, die auch dieses Interface implementiert.
Dann noch eine RS-232-Klasse
Und eine Consolen-Klasse: SendMEssage => WriteLn und QueryResponse = 'WriteLn' und 'ReadLn'... Sehr schön zum testen.
Und eine Buschtrommel-Klasse mit Mikrofon, Lautsprecher und Samples.
Und eine LTE-Klasse
Und.
Und.
Und.

Deine Anwendungen, die dieses Interface verwenden, werden auch mit einer LTE-4G-Astromedial-Klasse funktionieren. Und, besser noch: Sie müssen noch nicht einmal neu kompiliert werden (wenn man die Klasse per Plugin aus einer DLL lädt, z.B.)

In einem Edit meines Beitrags habe ich angemerkt, dass diese Flexibilität auch einen Preis, nämlich eine entsprechend größere Anwendungsdatei hat, da auch die Implementierungs-Klassen für alle unbenutzten Message Broker eingebunden werden.
(Man könnte aber durch Einsatz von IFDEF verschiedene Versionen der Anwendung erstellen, die je nach Bedarf nur einen Message Broker oder eine Auswahl (zwei bis N) unterstützen.)
Dann doch lieber Plug-Ins.
  Mit Zitat antworten Zitat
mjustin

Registriert seit: 14. Apr 2008
3.011 Beiträge
 
Delphi 2009 Professional
 
#4

AW: Interface richtig umgesetzt?

  Alt 23. Dez 2014, 14:51
Fertig ist das allgemeine Client-Interface
Delphi-Quellcode:
Type
  IClientConnection = Interface
    procedure StartConnection (server : IServer);
    procedure SendMessage (message : String);
    procedure QueryResponse (query : String; var response : String; timeout : Integer);
    procedure StopConnection;
  end;
Oder auch so:
Delphi-Quellcode:
type
  IConnection = interface
    procedure Start;
    procedure Send(AMessage: string);
    function Receive(ATimeout: Integer): string;
    procedure Stop;
  end;

  IMessageBrokerClient = interface
    function CreateConnection: IConnection;
    ...
  end;
Im Interface fehlt noch die Angabe des Queuenamens (oder allgemeiner: Destinationnamens, da es neben Queues auch Topics oder Channel gibt, die Begriffe sind nicht einheitlich über alle Broker). Man könnte den Destinationnamen zum Beispiel als Argument beim Erzeugen der Connection übergeben.
Michael Justin
  Mit Zitat antworten Zitat
Benutzerbild von TheMiller
TheMiller

Registriert seit: 19. Mai 2003
Ort: Gründau
2.480 Beiträge
 
Delphi XE7 Architect
 
#5

AW: Interface richtig umgesetzt?

  Alt 23. Dez 2014, 14:53
Hi,

Dejan Vu, das habe ich soweit verstanden. So habe ich es auch umgesetzt (nur, dass bei mir erstmal alles auf Broker zugeschnitten ist, da ich TCP verworfen habe. Aber okay, lassen wir es mal bei deiner Skizze).

Ich dachte, dass das Interface mir ermöglicht, dass ich meinen Quelltext nicht ändern muss, wenn ich den Broker tausche (in meinem Fall). Also, dass ich im Programm selbst nur gegen TAllgemeineKlasse programmiere, welche dann im Hintergrund die geforderten Broker benutzt.

In deinem Beispiel muss ich ja dann jeden Aufruf von TTCPClientConnection in TMSMQClientConnection ändern. Und ich dachte, dass mir das Interfaces ersparen. Daher habe ich meine Klasse TMy_MQ erstellt, gegen die ich programmiere.

Es kanna aber auch wirklich sein, dass ich das mit den Interfaces noch missverstehe.
  Mit Zitat antworten Zitat
mjustin

Registriert seit: 14. Apr 2008
3.011 Beiträge
 
Delphi 2009 Professional
 
#6

AW: Interface richtig umgesetzt?

  Alt 23. Dez 2014, 15:01
In deinem Beispiel muss ich ja dann jeden Aufruf von TTCPClientConnection in TMSMQClientConnection ändern. Und ich dachte, dass mir das Interfaces ersparen.
Das ist sicher ein Missverständnis: die konkrete Klasse wird im Programm nur an einer Stelle benötigt, um einen Interfacezeiger zu erhalten, ab diesem Punkt wird dann nur noch mit dem Interface gearbeitet.

Falls im Programm an verschiedenen Stellen eine neue Instanz der Klasse benötigt wird, kann man die Erzeugung in eine zentrale Factorymethode auslagern. Auch dann wird nur ein Mal die konkrete Klasse eingebunden.
Michael Justin
  Mit Zitat antworten Zitat
Benutzerbild von TheMiller
TheMiller

Registriert seit: 19. Mai 2003
Ort: Gründau
2.480 Beiträge
 
Delphi XE7 Architect
 
#7

AW: Interface richtig umgesetzt?

  Alt 23. Dez 2014, 15:04
die konkrete Klasse wird im Programm nur an einer Stelle benötigt, um einen Interfacezeiger zu erhalten, ab diesem Punkt wird dann nur noch mit dem Interface gearbeitet.
Kannst du mir dafür ein konkretes Beispiel geben? Das ist genau das, was ich meine bzw. was ich nicht verstanden habe!

Danke
  Mit Zitat antworten Zitat
mjustin

Registriert seit: 14. Apr 2008
3.011 Beiträge
 
Delphi 2009 Professional
 
#8

AW: Interface richtig umgesetzt?

  Alt 23. Dez 2014, 15:22
Kannst du mir dafür ein konkretes Beispiel geben? Das ist genau das, was ich meine bzw. was ich nicht verstanden habe!
Angenommen in der Applikation ist eine MSMQBrokerClient Klasse als private Property "MyMSMQBrokerClient" erzeugt worden.

Diese eine Instanz wird dann in einer Factory Methode verwendet die eine Connection liefert:

Delphi-Quellcode:
function TMyApp.CreateConnection: IConnection;
begin
  Result := MyMSMQBrokerClient.CreateConnection;
end;
Und dann kann im Programm an beliebigen Stellen - die natürlich auf die MyApp Instanz zugreifen können - eine Connection erzeugt und geöffnet werden, zum Beispiel in einem Thread.

Delphi-Quellcode:
procedure TMyDoWorkThread.Execute;
var
  Conn: IConnection;
  Msg: string;
begin
  Conn := MyApp.CreateConnection;
  Conn.Start;

  while not Terminated do begin
    Msg := Conn.Receive(1000);
    // mach etwas mit der erhaltenen Nachricht...
  end;

  Conn.Stop;
end;
(Exceptionbehandlung für Verbindungsverlust etc. mal weggelassen).
Michael Justin
  Mit Zitat antworten Zitat
Benutzerbild von TheMiller
TheMiller

Registriert seit: 19. Mai 2003
Ort: Gründau
2.480 Beiträge
 
Delphi XE7 Architect
 
#9

AW: Interface richtig umgesetzt?

  Alt 23. Dez 2014, 16:16
Ok, verstanden.

Hab gerade etwas rumprobiert und gesehen, dass in deinem Beispiel MyMSMQBrokerClient.CreateConnection einen Zeiger auf IConnection zurückgibt (denke ich).

Doch ich bekomme den Inhalt für "CreateConnection" nicht hin. Was muss ich konrekt reinschreiben, um eine IConnection zurückzubekommen?

Danke für eure Geduld

EDIT

Ich glaube, ich habe es!

Interfaces - Die Klasse TMyMQ wird gelöscht, da überflüssig (wie vermutet)

Delphi-Quellcode:
IMy_MQ = interface
...
...
end;

TMy_MSMQ = class(TInterfacedObject, IMy_MQ)
...
...
end;
und hier kommt in der programmweiten Verwendung der Knackpunkt. Es wird nicht TMy_MQ erstellt, sondern direkt eine Variable IMy_MQ, welche dann via TMy_MSMQ.Create mit dem Interfacezeiger gefüllt wird:

Delphi-Quellcode:
procedure TForm1.Button2Click(Sender: TObject);
var
  mq: IMy_MQ;
begin
  mq:=TMy_MSMQ.Create;
  mq.SendMessage;
end;
Richtig? Es funktioniert jedenfalls. Aber hatte meine erste Version ja auch

Geändert von TheMiller (23. Dez 2014 um 17:04 Uhr) Grund: Hatte eine Erleuchtung!
  Mit Zitat antworten Zitat
Ursa

Registriert seit: 5. Jan 2015
5 Beiträge
 
#10

AW: Interface richtig umgesetzt?

  Alt 5. Jan 2015, 06:48
Du diese Klasse nun doch an die Implementierung koppelst.




samsung galaxy A5 schutzhülle

Geändert von Ursa ( 6. Jan 2015 um 02:27 Uhr)
  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:32 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