Connecting Senders to Receivers | Design Patterns

Nitish Sharma
5 min readJun 29, 2022

--

In software development, there can be various instances where we need to establish a connection among objects which can send and receive a request. Also some of those instances might be often. And as we know that we have predefined Design Patterns which are a kind of blueprint and provide us the solutions to some common and frequent software design problems. Let’s see how design patterns can help us in connecting senders to receivers.

In this article I am going to discuss four different situations where we need to establish a connection among senders and receivers of a request. And we will see how four different design patterns can help us in those situations. The intention here is to come up with a loosely coupled and easily extensible design. So, let’s get started.

Scenario 1
when your program expects to process different types of requests in different ways but the exact type of request is decided during runtime.

To understand our first scenario let’s take an example. Consider that you’re working for a customer support system where you need to handle support requests based on its severity, which can either be MINOR, MAJOR or CRITICAL. Here the request can be of three different types which might need to be handled differently. In this type of situation Chain of Responsibility design pattern can be of use where we can define three separate handlers/receivers for the requests based on the severity and we can pass the request in a chain of handlers where one of them will handle it.

You can find the code example here.

Look at the below diagram to understand better.

Chain of Responsibility Pattern

Chain of Responsibility:
It helps a sender to pass a request along a dynamic chain of receivers maintaining an order until one of the receivers handles it. Each receiver object is responsible for a particular type of task and It can either handle the request or can pass on the request to the next receiver/handler in the chain.

CoR can also be helpful

  • When we have to execute several handlers in particular order.
  • When the order of handlers are supposed to change at runtime.

Scenario 2
when you want to turn a request into a stand-alone object that contains all information about the request.

This statement might not look very clear but sometimes we may want to transform a request into an object so that we can pass the request as method argument, or we can delay/schedule the execution of request, or we want to make it an undoable action.

Let’s try to understand this with an example. Suppose you’re working on a product trading application where users can buy or sell products. Let’s say we have a Broker class which is a bridge between client and the product i.e sender and receiver of the request and there is a method placeOrder() in it. Now we can easily implement this placeOrder() method as something like this:

placeOrder(type: String) {
If type is “BUY”
product.buy()
Else if type is “SELL”
product.sell()
Else
Log “Operation Not Found!”
}

But here the problem is placeOrder is tightly coupled with the actions performed on Product. So, if we want to achieve a loosely coupled design where the Broker is not concerned about how the order is being placed, we can use the Command Pattern. As per this pattern we can turn “BUY” or “SELL” operation into commands on a Product and pass the required command object as a parameter to placeOrder() method and simply call command.execute() method inside it.

Have a look into the code example here.

And here is a diagram to understand better.

Command Pattern

Command Pattern
This design pattern helps us establish a unidirectional connection between a sender and a receiver. It creates objects that encapsulate actions and parameters.

We can also use this pattern

  • When we want to schedule the execution of a command
  • When we want to perform undoable/reversible operations

Scenario 3
When some classes are tightly coupled with several other classes and are hard to maintain.

A good system design is when we have loosely coupled and reusable components. However, in real life we often need to deal with several complex interdependent objects. In this situation the Mediator Design Pattern comes in handy.

To understand this, let’s say you’re working on a banking application where you’ve Account object. Now you want to generate a statement for that account. Let’s say it takes help of another Statement class which again makes use of TranactionHistory class while generating statements. Lot of dependency, right? Here we can create an intermediate AccountMediator class which can prevent the direct communication of these objects. Account can take help of AccountMediator to generate statements whereas Statement can also take help of AccountMediator to get TransactionHistory details.

You can find the code example here.

Have a look into this diagram to understand better.

Mediator Pattern

Mediator Pattern
This design pattern prevents direct connection between a sender and a receiver, and helps them communicate indirectly through a mediator object.

we can use this pattern

  • When some classes are tightly coupled with other classes, and it’s difficult to change them.
  • When you can’t reuse a component in a different program because it’s too dependent on other components

Scenario 4
When changes to the state of one object require change in other objects.

Consider you’re working for an application where you need to update every user whenever there is any change in User’s Privacy Policy. In this type of scenario we can use the Observer Pattern where we can have a PrivacyPolicyHandler which can work as a publisher/sender and It can have a list of users as subscribers/receivers which will get notified every time there is a change in policy.

You can find the code example here.

Have a look into this diagram.

Observer Pattern

Observer Pattern
This design pattern helps a receiver to subscribe to or unsubscribe from receiving a request from the sender. It’s a publish/subscribe pattern and allows a number of observer/subscriber objects to see an event. A publisher can have a dynamic list of subscribers.

I hope this read was valuable for you and it helped you understand how different design patterns can help us in different situations. You can find code examples of some more design patterns in this repo.

References:

--

--

Nitish Sharma
Nitish Sharma

Written by Nitish Sharma

Senior Consultant - Application Developer at Thoughtworks, India. Checkout nitishsharma.dev

No responses yet