Mediator Design Pattern In Action! - C# Design Pattern Tutorial
December 1, 2023
• 9,217 views
In this video, we'll be exploring the mediator design pattern. This design pattern is used to manage communication between different objects. We'll navigate a small sample application using the mediator design pattern and C#.
If you're interested in learning more about design patterns or want to learn how to use C# to create powerful applications, this video is for you! By the end of this video, you'll have learned everything you need to know about the mediator design pattern and how to use it...
View Transcript
in this video I'm going to walk you through a tutorial on the mediator design pattern in C together we're going to walk through a really simple hypothetical chat application that demonstrates how this pattern works now in some earlier videos that I put out I was demonstrating how the Observer pattern works and we showed a couple of different flavors of how you go create that but with the Observer pattern something that we run into is that you have a bit of coupling with how the Observer and the observ BS interact with each other they need to really understand and know about each other and therefore those in es those classes are kind of coupled together the idea behind the mediator pattern is that it starts to separate this out a little bit for us so instead of having two objects communicating directly with each other and
therefore having full knowledge about each other's existence instead they wrote messages through a mediator so the mediator acts as this middleman in the system that you're communicating with and therefore the messages go to it and it's responsible for being able to route to the right places this means that your objects that want to communicate only really have to understand how to communicate with the middleman the mediator in this case and by doing that it's decoupling the things that want to talk with each other from each other they're only sort of coupled to this mediator API that they have to work with before I jump over to visual studio just a quick reminder about my free weekly software engineering newsletter there'll be a link in the comments below okay let's jump over to visual studio all right on my screen I have a really small mediator
chat application that we can see in action the first part that you see on the screen is really just about 11 lines of code here that demonstrate how we're going to set up these three different users register them to a mediator and then demonstrate how this user can send a message but we'll see how this all works and we're going to start by jumping down right to the chat user so I'm going to expand this on line 46 and we'll check it out together so the chat user that I have here is going to take in an instance of the mediator and that's because we're going to use that mediator as our mechanism to communicate with other chat users and the other thing thing we're going to do is every chat user that we create we're going to give a name and that way we
can identify it so you can see that we're passing those in here and we store those right here in these private variables if I scroll down a little bit lower every chat user has a send message and receive message and what's important to note is that when we talk about sending messages if you recall what I said in the opening part of this video we are not coupling ourselves to the things that we want to be able to send messages to so if you think about it in a chat program we want to send messages to other chat users but if you look at the code that I have written here you can see that to either receive or to send messages we don't actually require any knowledge about the destination that we want to send to in fact the only thing that we care
about is sending messages to the mediator and that's because we trust that when we send the message to the mediator with the right information it's able to get our message to the right destination and it's important to reiterate that so when we go to send a message we don't have to know anything about the type of the destination that we're sending to and therefore we're not coupled to the API of the receiving end all that we have to do is be able to communicate with this mediator and trust that it's going to do the work for us if we look at the receive message Api it's only going to take in this message so we're going to have to check out the mediator implementation to see how that ends up calling receive message on the user something to think about as we go forward and
check out that mediator is to look at this console right line here so this particular right line is saying that the current user so that's where this underscore name comes from has received a message and it's the message that we got from the mediator what we don't have passed in is any information about the sender now something that would create a little bit of coupling is if we ended up putting an i user here so we're not going to have an i user that is the sender provided like this but instead we can go make a quick tweak to make sure that we can get the sender in a different way I also have no idea why I didn't use string interpolation here I don't think I've written code like this in ages so that's kind of funny to see but that's better that hurts
my eyes a little bit less all right let's go check out the mediator and see how that implementation actually works so the chat mediator is going to have a list of users that we're able to register and if you're thinking about a chat application and this could look different in whatever application you're creating in our chat application we need to keep track of all of the users that we can chat with and I want you to think about either a chat room or a conversation where all these users are and that's going to mean that when we send a message to the mediator from a chat user we essentially want that to be broadcast to the other users we're going to be talking with all of them at the same time so that means if we go to check out this send message implementation on
the mediator takes in the message that we want to send and then who the sender is and the reason that we need to know who the sender is is because if we look at the implementation and again this is going to look different for different mediator implementations we don't want to send to the sender and that makes sense right so if we go to iterate over every user that's registered in the mediator we just want to make sure that the sender who's trying to send that message to everyone else is also not going to receive the message that it's trying to send out it doesn't make a whole lot of sense for our little chat application because the idea is to mimic a little chat room or a little conversation but if you recall I did say that when we go to have this receive
message call we don't end up getting the user that's the sender and I was stating that if we go to have receive message here on the user API that would mean if we passed in an i user we're essentially saying that we can only communicate by getting messages from other I users so I want to pause for a second here because when I'm talking about coupling I'm talking about the different types that we're talking with what you'll see when we go back to the code is that the send message Api that we have on the mediator is in fact a little bit odd because it does require that we can only be sending from an i user now the nice thing about the interface implementation here with I user is that we can have different implementations of a chat user but the reality is is
that we're kind of coupled to anything that's an i chat user and we can break away from this a little bit further in fact by removing the I chat user from that API on the mediator as well as getting sender information by providing a little bit of extra information instead and the reason I wanted to pause to explain this is because the point of the mediator pattern is supposed to be that it's helping us decouple systems that want to talk with each other if I want to send a message to a destination I don't have to know the API that it's working with I can communicate with a mediator this middleman something in the middle that I know how to talk to I can give it enough information about what I want to send and enough information that it needs about getting that message to
the destination or destinations and from there I don't have to worry if the receiving end changes code changes implementations whatever else I'm completely unaffected in my code all that I know is I talk to that mediator and things work how I want so let's jump back to visual studio tweak this code a little bit and make sure that we can get the sender in our received message information all right we're going to start by refactoring the send message Api and I was saying that I want to get rid of this sender information here instead what we're going to do instead what we'll do is just pass in the name we don't need the whole type we just want to have something that can be identified here and now that we just have the name pass in we can go think about how we want to
change this receive message Api to also take in a name from the center that way we end up having a sender and a message and I'll rename this once more to make it a little bit more understandable so with sender name being passed in what we can start doing is checking the other users to make sure they don't have the same name as the sender name and the one thing that we did not do is expose the name property on our user and I'm just going to go modify that on the interface first of all so we'll go expand this and then add the property for the name and then I'm just going to quickly update the chat user to have a name property instead then I'm just going to go update the other other two instances where we're using that property now if we
have a quick look while I'm down here we can see that the send message Api changed on the mediator and visual studi is indicating that to us because this is not going to be applicable anymore we're no longer passing in an instance of an i user instead we need the sender name and then the message that we're sending in I'll just use name parameters here to make this a little bit more readable for this video so far so good right if we're taking a look at this API call that we have to make this mediator method send message doesn't require any information about the type of the destination we're going to so from the perspective of this chat user class that we're in send message does not have any restriction or requirement about who can send messages or where they're going and the same thing
is applicable for receive message but if you recall we did want to make sure that we could pass in the name of the sender in the receive message method so I'm going to go ahead and do that here now that we're passing in the sender name I'm just going to quickly update this right line to make it more obvious where this message is coming coming from and finally one more spot to go update because I didn't use the built-in refactoring methods in Visual Studio is the interface that we've defined for the user all that I need to do is put on the sender name right here and that way when we're receiving a message we know who it's coming from now we're not quite done modifying this so let's go right back to our mediator where we were sending the message and where we left
off when we were first looking at this was that we no longer are able to compare the user to the sender we need to be able to compare the names and make sure that we're not sending it to the same name and in theory that should be good enough for us to be able to send messages now and a quick note if you're thinking about the scenario that we have which is a little fake chat application this means that we can't have users with the same name previous code that we had was comparing the instances and that would mean that you could have three people named Nick and that would be okay because if they were different instances of chat users the receivers would not be the same as the sender and that could have worked with this change that I've now made the username
must be unique and I would personally suggest if you're making chat applications try not to compare against the user's name it would probably be more wise to be able to check out a user ID and the same pattern kind of goes for other entities that you might be dealing within systems names are probably things that aren't always unique but you can come up with patterns that help you have more unique identifiers now that this code's been updated let's have a quick pass through everything just to make sure it makes sense first we've gone ahead and updated our I user interface to be able to have a name property and we also changed the receive method to be able to know who the sender is and if we quickly check out the chat user we should see that this is the same thing that we're seeing
on the interface right so we have that name property we are also now on the mediator which we'll go check out right after providing our own name as the sender and then the message that we want to send and this receive message has now been updated where we can see the sender name in this console right line if if I jump over to the mediator implementation we can see that we modifi the send message to be able to take in a sender name and a message instead of a message and an i user instance the other change we made was this name comparison which we just talked about as well as this receive message call which is now passing in the sender name and the message you might still be saying well Nick this chat mediator still depends on I users in fact we need
to register I users into this chat mediator in order for this to work so how could this possibly be decoupled well that wasn't the point of what I was trying to get across the point I was trying to get across was that for sending messages we're no longer coupled to specific implementations of who can send and who can receive based on this API and that means if you wanted to mix and match different ways to be able to send between and receive from different things you could go ahead and make a completely different mediator that supports that but now the moment you've been waiting for is what happens when we go and run this thing well let's go find out and thanks to our awesome ref factoring that we did we were able to get our mediator up and running and have the sender included
in the message that's printed out so we can see that the user one is sending the message hello everyone and the only two others that receive it because you'll notice user one is not receiving it but user 2 and user 3 received the message hello everyone from user one and unfortunately I left out the word from here so I messed up the demo but you can get the idea that this is coming from user one all right aside from my little mixup at the end there with forgetting the word from in the console right line you can see that this is a pretty simple implementation of a mediator pattern the entire Point behind the mediator pattern is that we want to decouple our sender and receiver from each other now the mediator itself is technically receiving messages but it's acting as the middleman in the
system for your communication that way the people who want to send messages or publish them out go to the middleman this mediator and the receivers are able to get that based on how the mediator sends those messages through something about the Observer pattern that we observed in my last videos or if you've seen this in other places is that the Observer and the observable are very coupled together in terms of knowledge about each other that can be okay in some systems and in other systems you want to have this obvious decoupling and that's going to wrap up the mediator pattern for today so if you enjoy the little refactoring exercise we did there you can actually check out the chorus I've released and that's going to be in the pin comments below and you can also watch this video next thanks and we'll see you
next time
Frequently Asked Questions
What is the main purpose of the Mediator Design Pattern?
The main purpose of the Mediator Design Pattern is to decouple objects that want to communicate with each other. Instead of having objects communicate directly, they send messages through a mediator, which acts as a middleman. This way, the objects only need to know how to communicate with the mediator, reducing their dependencies on each other.
How does the Mediator pattern improve upon the Observer pattern?
The Mediator pattern improves upon the Observer pattern by reducing the coupling between the sender and receiver. In the Observer pattern, observers need to know about the observable, leading to tight coupling. In contrast, the Mediator pattern allows objects to communicate through a mediator without needing to know about each other's existence, making the system more flexible and easier to maintain.
Can you explain how messages are sent and received in the chat application example?
In the chat application example, each chat user sends messages to the mediator instead of directly to other users. The mediator then routes the messages to the appropriate recipients. When a user sends a message, they provide the message content and their name to the mediator, which ensures that the sender does not receive their own message, maintaining a clean communication flow.
These FAQs were generated by AI from the video transcript.