2012-07-06 7 views
5

Desde una aplicación cliente, estoy enviando una solicitud/transacción (que contiene una operación para realizar (y parámetros) + ID de transacción) a una cola remota. El servidor remoto dequeue la solicitud en algún momento y toma un tiempo para procesarla.Necesita un mejor diseño para un componente "despachador de rellamada"

Una vez hecho el procesamiento, envía una respuesta en la cola del cliente (que contiene la respuesta aplicativa + el transactionID) ... así que este es un modo de comunicación totalmente "desconectado", la única forma en que el cliente puede mapear la respuesta a la solicitud es a través del transactionID.

La respuesta del mensaje se quita de la cola del lado del cliente y se compara con la solicitud original (en función del transactionID).

Lo que estoy haciendo ahora es que cuando el cliente publica la solicitud en la cola del servidor, agrega una devolución de llamada a un dictionnary manteniendo transactionId y callback (delegado). Este es un Dictionary<int, object> mapeando una transacciónId a una devolución de llamada para llamar con el resultado de la operación.

Las devoluciones/delegados se almacenan como objetos debido a que dependiendo de la solicitud, la firma del delegado de devolución de llamada es diferente (por ejemplo, una respuesta puede devolver List<string> mientras que otra respuesta puede devolver int).

Cuando la cola del cliente dequeue una respuesta, conoce el tipo de respuesta (y por lo tanto la correspondiente firma de la devolución de llamada), por lo tanto obtiene la devolución de llamada del diccionario, en función del transactionID. A continuación, devuelve el objeto al tipo de delegado correspondiente e invoca la devolución de llamada.

Me parece que este enfoque no es muy "sexy", pero realmente no veo otra forma de realizar esa tarea.

¿Hay alguna forma mejor de realizar esto?

Si el problema no es lo suficientemente claro, hágamelo saber y aclarará con algunas ediciones.

+0

posible duplicado de [C#: ¿Está utilizando Aleatorio y OrderBy un buen algoritmo de mezcla?] (Http://stackoverflow.com/questions/1287567/c-is-using-random-and-orderby-a-good-shuffle -algorithm) – Arion

Respuesta

3

Puede encontrar que las Extensiones reactivas son una herramienta útil para ese tipo de mensajes.

Primero, haga que todas sus respuestas implementen alguna interfaz o clase base, como IMessage. Cada tipo de respuesta debe ser encapsulado en una clase separada como aquí

public interface IMessage 
{ 
    int TransactionId { get; } 
} 

public class UserListMessage : IMessage 
{ 
    int TransactionId { get; set; } 
    public List<string> Users { get; set; } 
} 

luego hacer su cola de mensajes implementar IObservable<IMessage>. Las extensiones reactivas proporcionan una implementación lista para usar llamada Subject<T>, es posible que desee envolverla o algo así.

Observable implementa un método Subscribe(IObserver<IMessage> observer) que almacena observadores en algún lugar de una lista interna. Cuando llega una nueva respuesta, se llama a un método OnNext(IMessage message) en cada observador suscrito.

Por último, el código de registro la gestión de respuesta podría ser:

var subscription = myQueue 
    .OfType<UserListMessage>() 
    .Where(msg => msg.TransactionId == id) 
    .Subscribe(callback); 

que registrará un mensaje de devolución de llamada para el tipo de UserListMessage con identificador de transacción dada. Probablemente también desee darse de baja en algún lugar. Eso será:

subscription.Dispose(); 

Esa fue una breve muestra de cómo se vería con Rx. Ahora ve y encuentra un tutorial más detallado.

1

Puede crear una enumeración, en el lado del cliente, que defina todo el tipo de posibles respuestas que pueda obtener. Luego puede codificar una función que contenga un gran "caso de selección" que asocie cada valor de la enumeración a su llamada de función específica. Luego puede asociar el transactionID al valor de la enumeración que identifica el tipo de respuesta que recibirá del servidor.

Dependiendo del tipo de funcionalidad que necesita implementar en cada tipo de respuesta, tal vez pueda encontrar una forma más "orientada a objetos" de hacer las cosas ... Tal vez pueda crear una clase base ResponseAction, con método de respuesta común, y luego puede heredar de esta clase para cada tipo de respuesta posible que pueda obtener, y luego cuando llama al servidor, crea una instancia de la clase Response_Specific_Action correcta y coloca esta instancia en el diccionario ... y luego en cada respuesta utilizará su diccionario para encontrar la instancia correcta, y llamará al mismo método Respond estándar, y usará su implementación "específica" Response_Specific_Action.

Si elige la ruta de la clase ResponseAction, también puede considerar incluir el transactionID como una propiedad de la clase base.

1

Tu situación de alguna manera no es muy clara para mí. En primer lugar, ¿no mencionó qué mecanismo de comunicación está utilizando durante la transacción del servidor cliente? ¿Estás usando WCF y sus 'canales de devolución de llamada?

¿por qué no ajusta todos sus mensajes de respuesta de solicitud en la clase base que tiene algunos datos comunes para todas las transacciones?

u triste está utilizando la Lista para su diccionario porque, la respuesta difiere de una transacción a otra, pero de nuevo ¿por qué objeto? ¿no es más difícil tener un contrato común para todos los mensajes de respuesta? Cuéntenos un poco más sobre el flujo de comunicación entre su cliente y el servidor

1

Esto suena exactamente como un problema de patrón de adaptador. Consulte this link para obtener una buena visión general del adaptador.

Lo que necesita hacer es crear una abstracción que encapsule toda la respuesta del cliente (incluyendo lo que sea que haga con eso List<string> o int). Su abstracción debe ser lo suficientemente amplia como para que sus comportamientos variables puedan estar cubiertos por la misma firma. Algo como esto:

public abstract class MessageCompleteHandler 
{ 
    public abstract void Execute(); 
} 

//name this one better, just an example :) 
public class ListOfStringHandler : MessageCompleteHandler 
{ 
    public override void Execute() 
    { 
     //get list of strings 
     // do something with it 
    } 
} 

public class MessageCompleteHandlerFactory 
{ 
    public MessageCompleteHandler GetHandler(int transactionId) 
    { 
     //this replaces/uses your dictionary to match handlers with types. 
    } 
} 

Entonces, cuando llegue la respuesta, se utiliza el ID de transacción para crear el objeto de contexto adecuado, y ejecutarlo. Esto funciona mejor si su número de variantes de controlador es bastante pequeño, por supuesto.

+0

Bien, pero ¿dónde está el adaptador aquí? – Pein

+0

Las implementaciones de MessageCompleteHandler son adaptadores sobre varios delegados; adaptando las diversas firmas a una sola interfaz. – tallseth

+0

No hay delegados en su muestra. Creo que no sabría cómo implementar su solución si quisiera. Actualmente se parece más a un patrón de comando, no a un adaptador. – Pein

Cuestiones relacionadas