Sistema de mensajería seguro, asíncrono y simplista para la comunicación entre clases / capas en Delphi creada por el equipo IPUB.
Delphi tiene su propio sistema de mensajería (System.Messaging.pas) que funciona bien, pero es totalmente sincrónico e inseguro. En los sistemas multiproceso, siempre necesitamos comunicarnos con otras clases, a veces sincrónicamente, a veces asincrónicamente, a veces sincronizando con el Read de Mainthread (en el caso de la UI), y hacerlo sin un sistema de mensajes (comunicarse directamente) hace que el código sea grande y complejo, propenso a muchos errores.
Un sistema de mensajería ideal sería un sistema seguro de subprocesos que permitiría que una clase se suscribiera y luego se denuncie para escuchar un mensaje en particular durante este tiempo, y esta clase de oyente que recibirá el mensaje es quién informará cómo el remitente invocará su método: en el mismo hilo ( publicación ), en el hilo principal ( principal ), en otro hilo ( asincrete ) y en un hilo que no sea el principal ( de fondo ). Esta es la base de nuestro sistema de mensajería, el uso es similar a otro sistema existente, el Delphi Event Bus (DEB).
Vea la comparación en un entorno con 1000 objetos:
| Suscribir | Correo | Cancelar la suscripción | |
|---|---|---|---|
| ipub | 1.6368 ms | 0.1215 ms | 1.7666 ms |
| DEBUTANTE | 9.8832 MS | 2.0293 MS | 4.0022 ms |
ILogOutMessage = interface
[ ' {CA101646-B801-433D-B31A-ADF7F31AC59E} ' ]
// here you can put any data
end ;Primero, debe suscribir su clase para escuchar mensajes, luego se suscribirá todos los métodos públicos que tengan el atributo [suscribirse].
TForm1 = class (TForm)
procedure FormCreate (Sender: TObject);
procedure FormDestroy (Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
[Subscribe(TipMessagingThread.Main)]
procedure OnLogout ( const AMessage: ILogOutMessage);
end ;
...
procedure TForm1.FormCreate (Sender: TObject);
begin
GMessaging.Subscribe(Self);
end ;
procedure TForm1.FormDestroy (Sender: TObject);
begin
GMessaging.Unsubscribe(Self);
end ;
procedure TForm1.OnLogout ( const AMessage: ILogOutMessage);
begin
Showmessage( ' Log out! ' );
end ;También puede declarar el método en parte protegida, pero para hacer esto necesita agregar {$ RTTI Métodos explícitos ([VCProtected, VCPublic, VCPublished])} antes de la clase.
var
LMessage: ILogOutMessage
begin
LMessage := TLogOutMessage.Create;
GMessaging.Post(LMessage);En los ejemplos anteriores, hemos mostrado un mensaje de interfaz, pero hay 3 tipos de mensajes:
| Identidad | Parámetro |
|---|---|
| nombre (explícito) | cadena |
| guía de la interfaz de parámetros (implícito) | interfaz |
| guía de la interfaz de parámetros (implícito) + nombre (explícito) | interfaz |
Para recibir mensajes con identidad de nombre, simplemente declare el nombre en el atributo de método:
[Subscribe( ' Name ' , TipMessagingThread.Main)]Para enviar mensajes con identidad de nombre, solo infórmelo en la llamada de publicación:
GMessaging.Post( ' Name ' , LMessage);Nota: El nombre explícito es insensible al caso.
En el atributo [suscribirse], puede determinar cómo se ejecutará el método que reciba un mensaje:
| Amable | Descripción |
|---|---|
| TipMessagingThread.posting | El valor predeterminado, el método del suscriptor se invocará en el mismo hilo de publicación donde se llamó a la publicación |
| TipMessagingThread.MAIN | El método del suscriptor se invocará en el hilo principal |
| TipMessagingThread.Async | El método del suscriptor se invocará asincrónicamente en un nuevo hilo anonnymous que no sea el hilo de publicación |
| TipMessagingThread.background | Si el hilo de publicación es el hilo principal, el método del suscriptor se invocará asincrónicamente en un nuevo hilo anonnymous, que no sea el hilo de publicación. Si el hilo de publicación no es el hilo principal, el método del suscriptor se invocará sincrónicamente en el mismo hilo de publicación |
Aunque el uso del atributo [suscribirse] para suscribir un método es muy práctico, es limitado porque debe definir el nombre del mensaje antes de la compilación, en el tiempo de diseño y, a veces, es realmente útil definir el nombre de los mensajes en tiempo de ejecución. Un ejemplo, un mensaje para un producto que se ha cambiado 'Product_105346_Changed', ese nombre de ese mensaje que solo puedo definir en el tiempo de ejecución, por lo que agregamos la opción de suscribir / cancelar la suscripción de un método para escuchar un mensaje manualmente:
GMessaging.SubscribeMethod<string>( ' product_105346_changed ' , Self.OnProductChanged, TipMessagingThread.Posting);
GMessaging.UnsubscribeMethod<string>( ' product_105346_changed ' , Self.OnProductChanged);Estos dos métodos manuales son independientes de los métodos de suscripción / cancelación de suscripción. Puede fusionar la misma clase con métodos suscritos utilizando automáticamente el atributo [suscripción] y llamar a suscribir / no suscribirse, y al mismo tiempo en esta clase con métodos que agregó manualmente utilizando suscriptemethod / unscribeMethod.
Otro beneficio de la inscripción manual de los métodos es que no se restringen solo a los métodos públicos (aunque este problema puede resolverse utilizando la Directiva de métodos explícitos RTTI).
La idea del sistema es solo reenviar mensajes, avisos, contener o no información, así que tenga en cuenta que no es aconsejable colocar códigos o códigos grandes con paradas (Waitfor) dentro de los métodos suscritos para escuchar mensajes, ya que esto afectaría directamente el rendimiento del sistema, incluso en modos asíncronos.
Otra consideración es solo un recordatorio de la forma correcta de usar Ttask de Delphi. Nunca use TTask para ejecutar métodos con paradas (eventos, semáforos, ...), no se hizo para eso, su objetivo es realizar tareas continuas y más simples, si su tarea es más compleja, lo correcto es usar un tthread. Le avisamos sobre esto, porque nuestro sistema utiliza la TTASK de Delphi para aumentar el rendimiento principalmente en entornos más complejos, además de guardar recursos, y si usa TTASK incorrectamente en sus códigos, puede hacer que su aplicación se congele al enviar un mensaje.
El mensaje IPUB tiene licencia en MIT, y el archivo de licencia se incluye en esta carpeta.