Message Factory and Message Interface Design Pattern
Distributed systems involve several communicating processors. The interfaces between these processors are often governed by interface documents and standard header files. The main objective of the Message Interface Design Pattern is to decouple the software from its external interfaces. This pattern also allows for a smoother role out of interface by maintaining backward compatibility.
Also Known As
- Interface Agent
- Message Handler
Software developers of distributed system resist changes in interfaces between modules. This is mainly due to:
- Making interface changes requires scheduling releases with the updates at the same time. This can be a logistic nightmare when teams working on different modules are not at the same location.
- Interface handling code and main logic of the module often get intertwined. Thus making interface changes difficult.
- Many times processors have different byte ordering and byte alignment conventions, this complicates interface design. (See the article on byte alignment and ordering)
This pattern addresses these issues as mentioned below:.
- The interfaces are defined to support backward compatibility, this reduces the effort involved in scheduling two independent software releases at the same time.
- The code for interface handling is decoupled from regular code, thus simplifying interface upgrades.
- Interfaces are packed to network conventions when sending the message. The messages are unpacked to native format when they are received.
This pattern can be used in the following cases:
- Modeling message interfaces with another processor within the system when the messages are packed at byte level.
- Modeling message interfaces with external modules (many times these messages are packed at bit level)
- Different messages supported by an interface are implemented as a class hierarchy. Each message class overrides the Pack and Unpack methods to define message specific packing and unpacking.
- Processor class contains a Message Factory class. Message Factory creates objects when the message type and version are specified.
- A ProcessorManager class might be defined when multiple processors with same message interface need to be supported.
The key actors of this design pattern:
- Processor: Base class that implements all the common functionality for all processors. Typically, classes representing processor interfaces would inherit from this class.
- MessageFactory: Message Factory creates a message object when the message type is supplied as a parameter.
- Message: Base class interfaces that are common to all messages.
The following diagram shows the relationship and collaboration between various classes involved in the Message Factory and Message Interface Pattern.
Use of this pattern has the following benefits:
- Message interface handling and rest of the logic are completely decoupled
- Introducing interface changes is easy as modules with new interfaces can also work with modules with older interface.
- Byte alignment and ordering considerations do not limit message interface design. There is less chance of bugs in this area.
The following scenarios are supported:
Setting Up Message Factory
- All message classes define a static method that creates an instance of the message by calling new.
- A function pointer to the above function, message type and version are passed to the Message Factory.
- Message Factory stores the mapping between message type, version and static message creation method.
Receiving a Message
- Application asks a Processor class to receive all messages from the OS queue.
- Processor obtains the message type and version from the message
- Message Factory is invoked with the message type and version
- Message Factory invokes the previously registered static method to create an object of the required type.
- The pointer to the message object is returned to the caller.
- Processor class now invokes Unpack for the message object and specifies the received message's pointer.
- Unpack method first unpacks the header of the message
- Once the header is unpacked, message specific field unpacking is done.
- After Unpacking is completed, the Processor specific message handler is invoked.
Sending a Message
- Application asks the Processor class to send a message object.
- The Processor class then invokes the Pack functionality to obtain a packed message.
- Packed message is passed to the operating system.
Sample Code and Usage
Any type of message interfaces can be implemented using this pattern. A few examples are:
- Standard telecom protocols like SS7, V5.2, ISUP, GSM, GPRS (Different versions of a protocol can be supported seamlessly)
- Byte level packing for proprietary protocols. This gives the protocols independence from byte alignment and ordering for a particular processor.