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
Benutzerbild von Sir Rufo
Sir Rufo

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

AW: Interface richtig umgesetzt?

  Alt 25. Dez 2014, 22:31
Wieso denn jetzt auf einmal OI? Möchtest du eine Komponente bauen?

Ja, kann man auch machen, würde ich allerdings nicht, denn warum sollte ich auf eine Form sowas draufklatschen, das gehört für mich ein paar Ebenen tiefer in die Anwendung.

Anyway, bauen wir uns also so eine Sende-Komponente:
Delphi-Quellcode:
// Basis Komponente für alle Send Queues
TCustomSendQueue = class( TComponent )
protected
  procedure DoSend( const AText : string ); virtual; abstract;
public
  procedure Send( const AText : string ); // ruft OnSend und DoSend auf
published
  // Ein paar Events?
  property OnSend : TNotifyEvent;
end;

// Konkrete Komponenten für MSMQ
TMSMQConnection = class( TComponent )
published
  property Server : string;
  property ...
end;

// Konkrete Ableitung für MSMQ SendQueue
TMSMQSendQueue = class( TCustomSendQueue )
protected
  procedure DoSend( const AText : string ); override;
published
  property Connection : TMSMQConnection;
  property Queue : string;
  property ...
end;
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 TheMiller
TheMiller

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

AW: Interface richtig umgesetzt?

  Alt 26. Dez 2014, 09:30
Guten Morgen.

Es tut mir schrecklich leid - ich habe mich vertran. Ich schiebe es mal auf meine Erkältung. Ja, ich schrieb OI, meinte aber lediglich die Codevervollständigung. Dort werden mir die weiteren Methoden nicht angezeigt. Eine Komponente macht da wirklich keinen Sinn.

Das Interface hat z.B. nur GetMessage, SendMessage. TMy_MSMQ hat darüber hinaus noch SetEncryption, IsActiveDirectory, etc.pp (alles fiktiv). Bei meinem Codebeispiel von oben sehe ich wie gesagt nur die Methoden des Interfaces Get/SendMessage. Ich weiß also nicht - außer mit einem TypeCast - wie ich auf die Methoden der KLasse zugreifen kann. Daher denke ich, noch irgenetwas falsch zu machen.

Dass ein Interface minimalistisch und allgemein gehalten werden soll, habe ich jetzt verstanden. Weiß daher jetzt auch, warum es nur Get/SendMessage zu haben braucht. Deine Erklärung mit Post etc. war echt gut. Es wird. Langsam, aber es wird

Danke (auch für die Geduld)
  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
 
#3

AW: Interface richtig umgesetzt?

  Alt 26. Dez 2014, 10:54
Aber warum willst du auf die Methoden der implementierenden Klasse zurückgreifen?

Wenn du eine Nachricht verschicken willst, dann benutze das Interface und verschicke die Nachricht. Es ist Aufgabe der implementierenden Klasse sich um den gesamten konkreten Versandablauf zu kümmern, denn nur die weiß, wie man z.B. mit MSMQ sprechen muss. Ich als Versender muss doch gar nicht wissen, was da intern alles passiert, es muss nur passieren.

Am sinnvollsten ist es dem Konstruktor der implementierenden Klasse alles mitzugeben, damit ich ein funktionierendes Interface bekomme.

Generell würde ich allerdings auch eine Trennung zwischen Sende- und Empfangs-Queue vornehmen (also 2 Interfaces). Die Möglichkeit besteht ja, dass ich x Sende-Queues und y Empfangs-Queues benötige. Und die Sende-Queue ist idR nicht die Empfangs-Queue (warum soll ich mir selber Nachrichten schicken).
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 TheMiller
TheMiller

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

AW: Interface richtig umgesetzt?

  Alt 26. Dez 2014, 13:48
Okay, habe ich jetzt so alles gemacht, wie du es gesagt hast. Leuchtet alles ein, funktioniert auch soweit.

Nur irgendwie werde ich den Verdacht nicht los, dass ich mich - zumindest bei den MessageQueues - mit den Interfaces einschränke. Ich habe nun zwei Interfaces, eines für das Senden, eines für das Empfangen. Habe jetzt auch zwei implementierende Klassen (obwohl ich die zusammenführen könnte - mach ich noch).

Wenn eine Nachricht gesendet wird, prüft die implementierende Klasse, ob es die Queue schon gibt. Wenn nicht, wird sie erstellt, dann geöffnet und die Nachricht eingetragen. Soweit okay. Der Versender kümmert sich also um nichts - wie ich bei der Post.

Beim Erstellen einer Queue kann man aber so viele Optionen angeben, wie übermittle ich die? zB Journal, Transaktionen (IsTransactional), Zugriff (IsWorldReadable), Verschlüsselung, ACL, etc. Und das sind nur die Optionen für das Erstellen einer Queue. Ich kann ja nicht alle Parameter, die ich irgendwann mal gebrauchen könnte, in dem Constructor definieren. Verstehst du mein Problem?

Allerdings habe ich auch verstanden, dass sich die Methode "SendMessage" um alles kümmern soll. Trotzdem habe ich noch obiges Problem. Würde ich nur eine Klasse erstellen, würde ich zwar die Vorteile des Interfaces verlieren, aber da hätte ich diese Probleme nicht. Habe ich noch ein altes Klassendenken?

Ach unabhängig davon: Wenn die Queue bei MSMQ nicht existiert, muss man um sie zu erstellen, einen Pfad benutzen, um sie zu öffnen/lesen/löschen einen Formatnamen. Also gibt es da auch wieder unterschiede, auf die ich nicht zu reagieren weiß.

Geändert von TheMiller (26. Dez 2014 um 13: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
 
#5

AW: Interface richtig umgesetzt?

  Alt 26. Dez 2014, 14:21
Anders herum gefragt:

Du hast da eine Poststelle wo alle ihre Post hinbringen, auf dass diese versendet wird.

Wer legt das konkrete Verhalten der Poststelle fest? Die Mitarbeiter, die ihre Post versendet haben wollen? Oder eventuell eher doch die Geschäftsleitung?

Und nochmal: Was interessiert es dich wie die Queue funktioniert (mit Transaktion oder ohne, mit Schleifchen oder Bändern, in rot oder grün) wenn du nur etwas versenden willst und du bekommst etwas geliefert, womit du versenden kannst.

Ich denke du springst zu sehr zwischen den Ebenen in deiner Anwendung hin und her.

Wenn die Anwendung z.B. ein Konstrukt aus Sende- und Empfangs-Queue benötigt, dann gib ihr das so
Delphi-Quellcode:
TFoo = class
  constructor Create( SendQueue: ISendQueue; ReceiveQueue: IReceiveQueue );
  // entweder Methoden
  procedure Send(...);
  function GetMessage(..):...;
  // oder als Eigenschaften
  property SendQueue : ISendQueue;
  property ReceiveQueue : IReceiveQueue;
end;
Und schon gehören die zusammen. Das ist wie Lego. Man hat kleine Steine und steckt sich da größere, spezialisierte Dinge zusammen.
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 Sir Rufo
Sir Rufo

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

AW: Interface richtig umgesetzt?

  Alt 26. Dez 2014, 14:29
Um nochmals die Poststelle aufzugreifen:

Die Poststelle kann ja durchaus mehrere Versandkanäle benutzen, die z.B. abhängig von Größe, Gewicht und Volumen genutzt werden. Die Mitarbeiter liefern trotzdem ihre Sachen an die Poststelle und die kümmert sich intern um die Bestimmung in welche Queu jetzt das geschoben wird.

Und der Empfang von ausserhalb geht auch durch die Poststelle und kommt aus unterschiedlichen Queues. Die Mitarbeiter bekommen davon nichts mit, denn die kennen nur ... die Poststelle.
Delphi-Quellcode:
TPostStelle = class( TInterfacedObject, ISendQueue, IReceiveQueue )
private
  FSendQueues : // Liste mit den möglichen Queues und dem Regelwerk, wann welche genutzt wird
  FReceiveQueues : // Liste aller möglichen Empfangs-Queues
public
  // Erzeugen mit allen benötigten Informationen
  constructor Create( SendQueueRuleSet: ...; ReceiveQueues : ... );
  procedure Send(...); // ISendQueue
  function GetMessage(...):...; // IReceiveQueue
end;
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
alda

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

AW: Interface richtig umgesetzt?

  Alt 26. Dez 2014, 15:37
Allerdings habe ich auch verstanden, dass sich die Methode "SendMessage" um alles kümmern soll. Trotzdem habe ich noch obiges Problem. Würde ich nur eine Klasse erstellen, würde ich zwar die Vorteile des Interfaces verlieren, aber da hätte ich diese Probleme nicht. Habe ich noch ein altes Klassendenken?
Ja, ich würde sagen das ist eine Mischung aus "altem Klassendenken" und vor allem alten Methodiken.

Ich denke Sir Rufo bringt es hier auf den Punkt:
Und schon gehören die zusammen. Das ist wie Lego. Man hat kleine Steine und steckt sich da größere, spezialisierte Dinge zusammen.
Das schwierigste hierbei ist die einzelnen Aufgaben und vor allem die verschiedenen Rollen (Post-Mitarbeiter, Kunde etc. ) korrekt zu identifizieren und zu implementieren (was hier ja sehr gut anhand des Post-Beispiels erläutert wurde). Was hierbei auch hilft ist einfach jede Implementierung zu testen - kannst Du eine Implementierung mal nicht richtig testen, ist Deine Klasse zu groß und Du solltest Dir was andres überlegen um den entsprechenden Code testbar zu machen. Wo man "früher" Funktionalität durch unzählige Vererbungshierarchien verfügbar (und untestbar) gemacht hat, liegt heute der Schwerpunkt auf der Aggregation von Funktionalitäten (den flexiblen Lego-Bausteinen).
  Mit Zitat antworten Zitat
Benutzerbild von TheMiller
TheMiller

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

AW: Interface richtig umgesetzt?

  Alt 26. Dez 2014, 16:46
Danke für die Antworten. Ich habe das alles jetzt mal umgesetzt und die Parameter in den Konstruktor gepackt. Das kann so nicht richtig sein.

Nochmal ganz konkret: Ja, ich rufe nur noch SendMessage() auf und die ganze Magie passiert in der implementierenden Klasse, weil mich das nicht interessiert was da vor sich geht. Okay. Doch wenn die Queue nicht existiertm, muss sie erst angelegt werden. Dann muss ich doch sagen können, wie sie angelegt werden soll.

Parameterübergabe entweder im Konstruktor oder garnicht. Richtig? Im Interface bei Send/Receive kann ich sie auch nicht übergeben, da die Send-Parameter bei MSMQ andere sind, also bei anderen Queues oder via TCP. Also müssten sie alle im Konstruktor übergeben werden - auch die, die vllt. gerade garnicht benötigt werden.

Oder muss ich mich dann auf Standard-Werte festlegen. Wenn eine Queue also nicht existiert, wird sie halt immer mit den von mir in der implementierenden Klasse festgelegten Standardwerten festgelegt. Also zB immer nicht transaktionell und nie weltlesbar.

Nun aber zur Umsetzung: Dies wären die möglichen Parameter:

MSMQ Create: Pathname, IsTransactional, IsWorldReadable
MSMQ Open: Formatname, Access (MQ_READ_ACCESS etc..), ShareMode
MSMQ Send: Subj, Body, DestinationQueue, Transaction
MSMQ Receive: Transaction, WantDestinationQueue, WantBody, ReceiveTimeout, WantConnectorType

Delphi-Quellcode:
  IMy_MQReceiver = interface
  ['{EECD3A9D-D9BC-4644-9D69-DADE10E65ED2}']
    function ReceiveMessage(): String;
  end;

  IMy_MQSender = interface
  ['{5C3F02B1-2E73-4500-9CD3-02EAFEDB332C}']
    function SendMessage(subject, msg: string): Boolean;
  end;

  TMQBroker = (mqMS, mqActiveMQ);

  TMy_MSMQ = class(TInterfacedObject, IMy_MQSender, IMy_MQReceiver)
  private

  public
    constructor Create(createPathName: String; createTransactional, createWorldReadable: Boolean; openAccess, openShareMode: LongInt; openFormatName: String; readTransaction: LongInt; readWantBody: Boolean; readTimeout; sendDestQueue: IMSMQQueue3; sendTransaction: LongInt);
    destructor Destroy();
    function ReceiveMessage(): String;
    function SendMessage(Subject, msg: String): Boolean;
  end;

// Und so könnte dann das Erstellen des Objektes aussehen:
procedure TForm1.Button4Click(Sender: TObject);
var
  mq: TMy_MSMQ;
begin
  mq:=TMy_MSMQ.Create('meineNeueQueue', false, false, MQ_READ_ACCESS, MQ_DENY_SHARE, '.\Private\meineNeueQueue', 0, true, INFITE, nil, 0);
end;
Ich habe verstanden, dass sich das implementierende Objekt um alles kümmern soll. Aber ich muss doch irgendwie Einfluss darauf haben, wie es die Queue im Notfall erstellen soll.

Habe mich gerade länger damit beschäftigen können und verschiedene Methoden ausprobiert. Bin jetzt gerade etwas verwirrt
  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
 
#9

AW: Interface richtig umgesetzt?

  Alt 26. Dez 2014, 17:26
Bis auf die Tatsache, dass du eine Schreib-Lese-Queue erzeugen möchtest ist das doch alles richtig. Ich wüsste keinen Fall, wo ich in ein und derselben Queue lesen und schreiben möchte. Queues sind One-To-One Verbindungen. Eine Nachricht in einer Queue wird von einem Empfänger empfangen. Will ich an mehrere Empfänger die gleiche Nachricht senden, dann muss die Nachricht auch in mehrere Queues.

Warum sollte es falsch sein, der implementierenden Klasse alles benötigte an die Hand zu geben um zu funktionieren?

Mal abgesehen, dass es für dich ungewohnt ist anscheinend nicht alles in der Hand zu haben, wo siehst du in deiner Anwendung das konkrete Problem?

Zeig doch mal etwas halbwegs konkretes, wo du beim Benutzen des Interfaces den Wunsch verspüren würdest, z.B. den Namen der Queue zu ändern, oder die Queue auf Transaktion umzustellen.

BTW

Das passt aber nicht
Delphi-Quellcode:
  IMy_MQReceiver = interface
  ['{EECD3A9D-D9BC-4644-9D69-DADE10E65ED2}']
    function ReceiveMessage(): String;
  end;

  IMy_MQSender = interface
  ['{5C3F02B1-2E73-4500-9CD3-02EAFEDB332C}']
    function SendMessage(subject, msg: string): Boolean;
  end;
Bei SendMessage hast du Subject und Message aber bei ReceiveMessage gibt es nur einen String zurück. Was kommt denn da? Subject, Message oder beides zusammengewürfelt?
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)

Geändert von Sir Rufo (26. Dez 2014 um 17:29 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 07:02 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