mardi 11 mai 2021

Design pattern to send out messages to multiple channels

I need to build a system that sends out messages to multiple channels: SMS server, Email server, 3rd party API and so on. I understand that Observer design pattern is a good approach to achieve this. But I'm not exactly sure how to capture the response of these notifications that are sent out.

For example: When a certain event happens, a message needs to be sent out to the user via SMS and EMAIL. The SMS and EMAIL observers will receive this message and send out the message. This process of sending of SMS/EMAIL can fail. And I need to record this. Not exactly sure how to record this.

The following is an attempt to solve this by using a MessageResponseHandler that is sent to the observer. The idea is that, after a message has been sent and response is received, the observer invokes the MessageResponseHandler which will define how to handle this response

// The message class
class Message {
    final int id;
    final String data;

    public Message(int id, String data) {
        this.id = id;
        this.data = data;
    }
}

// Interface for the observer
interface Observer {
    void send(Message message);
}

// Abstract implementation of the observer that handles the response
abstract class ObserverWithResponseHandle implements Observer {
    protected MessageResponseHandler responseHandler;

    ObserverWithResponseHandle(MessageResponseHandler responseHandler) {
        responseHandler = responseHandler;
    }
}

// Concrete implementation of sms observer, that sends out sms
class SMSMessenger extends ObserverWithResponseHandle {

    SMSMessenger(MessageResponseHandler responseHandler) {
        super(responseHandler);
    }

    @Override
    public void send(Message message) {
        System.out.println("Sending out SMS message");
        responseHandler.onComplete(message, true);
    }
}

// Concrete implementation of email observer, that sends out email
class EmailMessenger extends ObserverWithResponseHandle {

    EmailMessenger(MessageResponseHandler responseHandler) {
        super(responseHandler);
    }

    @Override
    public void send(Message message) {
        System.out.println("Sending out EMAIL message");
        responseHandler.onComplete(message, false);
    }
}

// Concrete implementation of 3rd party api observer, that sends out http requests
class ThirdPartyAPI extends ObserverWithResponseHandle {
    ThirdPartyAPI(MessageResponseHandler responseHandler) {
        super(responseHandler);
    }

    @Override
    public void send(Message message) {
        System.out.println("Sending out 3rd party API request");
        responseHandler.onComplete(message, true);
    }
}

// Interface that defines response handling on completion
interface MessageResponseHandler {
    void onComplete(Message message, boolean success);
}

// The subject which invokes the observers
class Subject {

    // Concrete implemnentation of response handler that simply prints to console
    MessageResponseHandler printHandler = (m, s) -> System.out.println("Response for message " + m.id() + "-" + s);

    // Adding the list of observers
    List<Observer> observers = Arrays.asList(
            new SMSMessenger(printHandler),
            new EmailMessenger(printHandler),
            new ThirdPartyAPI(printHandler)
    );

    // Invoking observers on a new message
    void onNewMessage(Message message) {
        observers.forEach(ob -> ob.send(message));
    }
}

public class Main {
    public static void main(String... args) {
        Message message = new Message(1, "THIS IS A NEW MESSAGE");
        Subject subject = new Subject();
        ....
        ....
        subject.onNewMessage(message);
    }
}

Aucun commentaire:

Enregistrer un commentaire