Design Pattern Examples
Overview of object-oriented design patterns
Mediator Pattern

Diagram of the Mediator pattern

The Mediator pattern acts as a go-between for multiple entities that want no knowledge of any of the other entities except at the most abstract level.

In effect, the Mediator class is a kind of router, with sufficient knowledge about all entities involved to facilitate communication among the entities without the entities themselves knowing anything about the other entities. The Mediator class also hides the details of the individual entities from the rest of the program (similar to the Facade Pattern).

The Mediator pattern requires introducing another class between the two (or more) classes that want to talk to each other. The intent is to model the communication between the two (or more) classes and make that model an object itself. In practice, though, the mediator is not something that can reused, although it does insulate changes in implementation of the various entities from everyone else.

What this means is the mediator is a class that becomes the point of contact in a system, exposing the other entities only in the most abstract way possible, typically though numerical or string identifiers.

A classic example of the mediator pattern is Users and Groups as objects. A User can be part of zero or more Groups and Groups can contain zero or more Users. There are a number of operations that can be done with this simple relationship:

  1. Determine all groups available
  2. Determine all users available
  3. Determine if a particular user belongs to a particular group
  4. Determine all users that are in a particular group
  5. Determine all groups that contain a particular user
  6. Remove a particular user from a particular group
  7. Add a particular user to a particular group
  8. remove a particular user from all groups
  9. Remove a user, which entails removing the user from all groups
  10. Add a new group
  11. remove a group
  12. Add a user

A mediator object for the above User/Group situation would have to know where to find the users and the groups and would provide functions for all of the above operations. That way, callers don't know about user and group objects except by name; all calls go to the mediator object that in turn knows how to find a particular user and group and how to search the groups, not to mention managing the lists of users and groups themselves.

[Note: It can be argued that managing the user and group lists from this mediator is too much functionality for one mediator class. On the other hand, it simplifies the calling interface for the application and makes the implementation of removing a user much easier; otherwise, the mediator that controls users would need to know about this mediator class and we're back to two classes knowing more about each other than is strictly necessary.]

The alternative is to have the caller go directly to the users and groups to perform the requests.

How to Use

Links to the Mediator classes or functions
C++ C# Python C
UserGroupMediator class UserGroupMediator class UserGroupMediator class Mediator_AddUser() function
Mediator_RemoveUser()
Mediator_AddGroup()
Mediator_RemoveGroup()
Mediator_AddUserToGroup()
Mediator_RemoveUserFromGroup()
Mediator_RemoveUserFromAllGroups()
Mediator_GetAllGroups()
Mediator_GetAllUsers()
Mediator_IsUserInGroup()
Mediator_GetUsersInGroup()
Mediator_GetGroupsWithUser()
Group class Group class Group class Groups_AddGroup() function
Groups_RemoveGroup()
Groups_FindGroup()
Groups_UserInGroup()
Groups_AddUserGroup()
Groups_RemoveUserFromGroup()
Groups_RemoveUserFromAllGroups()
Groups_GetAllGroups()
Groups_GetAllUsersInGroup()
Groups_GetGroupsWithUser()
GroupList class GroupList class GroupList class GroupList_Clear() function
GroupList_AddGroup()
GroupList_FindGroup()
GroupList_RemoveGroup()
User class User class User class User_Create() function
User_Destroy()
UserList class UserList class UserList class UserList_Initialize() function
UserList_Clear()
UserList_AddUser()
UserList_FindUser()
UserList_RemoveUser()

This example makes a further refinement by having the Users list and Groups list be objects themselves that can handle searching, adding, and removing entries. This simplifies the job of the mediator class. For example:

internal class User
{
public string Name { get; }
}
internal class Group
{
public string Name { get; }
public bool ContainsUser(string name);
public void AddUser(string name);
public void RemoveUser(string name);
}
internal class UserList
{
public User FindUser(string name);
public void AddUser(string name);
public void RemoveUser(string name);
}
internal class GroupList
{
public Group FindGroup(string name);
public void AddGroup(string name);
public void RemoveGroup(string name);
}
public class UserGroupMediator
{
void AddUser(string name);
void RemoveUser(string name);
void AddGroup(string name);
void RemoveGroup(string name);
void AddUserToGroup(string userName, string groupName);
void RemoveUserFromGroup(string userName, string groupName);
void RemoveUserFromAllGroups(string userName);
bool IsUserInGroup(string userName, string groupName);
string[] GetGroupsWithUser(string userName);
string[] GetUsersInGroup(string groupName);
string[] GetAllGroups();
string[] GetAllUsers();
}
Represents a single group. A group has a name and zero or more users. Users are tracked by name.
const char * Name
Name of this group.
Represents a list of groups. Call GroupList_Initialize() to start and GroupList_Clear() to release al...
Represents a user with a name.
Definition: Mediator_User.h:14
const char * Name
The name of the user.
Definition: Mediator_User.h:18
Represents a list of users. Call UserList_Initialize() to start and UserList_Clear() to release all r...

Here, the caller only sees the UserGroupMediator class object and all the functionality exposed on that class. The caller doesn't know how the users and groups are handled. In the same way, the User class has no knowledge of the Group class and vice versa.

Without the UserGroupMediator class, the caller would need to implement all those functions itself, with full knowledge of the User, UserList, Group, and GroupList classes, thereby exposing the implementation details of all those classes. With the UserGroupMediator class, the caller only needs to know the names of users and groups, which is generally supplied by the user that invoked the caller.

C++

void Mediator_Exercise()
{
std::cout << std::endl;
std::cout << "Mediator Exercise" << std::endl;
UserGroupMediator mediator;
//-----------------------------------------------------------------
// Operation 1: Determine all groups
std::cout << " Operation 1: Show all groups" << std::endl;
std::cout
<< Helpers::formatstring(" All groups: %s", _ListToString(mediator.GetAllGroups()).c_str())
<< std::endl;
//-----------------------------------------------------------------
// Operation 2: Determine all users
std::cout << " Operation 2: Show all users" << std::endl;
std::cout
<< Helpers::formatstring(" All users : {0}", _ListToString(mediator.GetAllUsers()).c_str())
<< std::endl;
//-----------------------------------------------------------------
// Operation 3: Does a user belong to a group
std::cout << " Operation 3: Determine if a user is a member of a specific group." << std::endl;
std::string userName = "Arthur";
std::string groupName = "admins";
std::cout << Helpers::formatstring(" Is user '%s' in the '%s' group?",
userName.c_str(), groupName.c_str());
std::cout
<< Helpers::formatstring(" %s", mediator.IsUserInGroup(userName, groupName) ? "Yes" : "No")
<< std::endl;
//-----------------------------------------------------------------
// Operation 4: Show all users in a group
std::cout << " Operation 4: Show all users in a specific group." << std::endl;
groupName = "Users";
StringList userNames = mediator.GetUsersInGroup(groupName);
std::cout
<< Helpers::formatstring(" All users in '%s' group: %s",
groupName.c_str(), _ListToString(userNames).c_str())
<< std::endl;
//-----------------------------------------------------------------
// Operation 5: Show all groups with a user
std::cout << " Operation 5: Show all groups containing a specific user." << std::endl;
userName = "Marvin";
StringList groupNames = mediator.GetGroupsWithUser(userName);
std::cout
<< Helpers::formatstring(" All groups with user '%s': %s",
userName.c_str(), _ListToString(groupNames).c_str())
<< std::endl;
//-----------------------------------------------------------------
// Operation 6: Show Remove a user from a group
std::cout << " Operation 6: Remove a user from a group." << std::endl;
userName = "Marvin";
groupName = "Power Users";
mediator.RemoveUserFromGroup(userName, groupName);
std::cout << Helpers::formatstring(" Removed user '%s' from group '%s'",
userName.c_str(), groupName.c_str()) << std::endl;
groupNames = mediator.GetGroupsWithUser(userName);
std::cout
<< Helpers::formatstring(" All groups with user '%s': %s", userName.c_str(),
_ListToString(groupNames).c_str())
<< std::endl;
//-----------------------------------------------------------------
// Operation 7: Add a user to a group
std::cout << " Operation 7: Add a user to a group." << std::endl;
groupName = "Users";
std::cout << Helpers::formatstring(" Adding user '%s' to group '%s'.",
userName.c_str(), groupName.c_str())
<< std::endl;
mediator.AddUserToGroup(userName, groupName);
groupNames = mediator.GetGroupsWithUser(userName);
std::cout
<< Helpers::formatstring(" All groups with user '%s': %s",
userName.c_str(), _ListToString(groupNames).c_str())
<< std::endl;
//-----------------------------------------------------------------
// Operation 8: Remove a user from all groups
std::cout << " Operation 8: Remove a user from all groups." << std::endl;
userName = "Arthur";
groupNames = mediator.GetGroupsWithUser(userName);
std::cout << Helpers::formatstring(" Removing user '%s' from all groups.",
userName.c_str())
<< std::endl;
std::cout
<< Helpers::formatstring(" Start: all groups with user '%s': %s",
userName.c_str(), _ListToString(groupNames).c_str())
<< std::endl;
std::cout << " Removing..." << std::endl;
mediator.RemoveUserFromAllGroups(userName);
groupNames = mediator.GetGroupsWithUser(userName);
std::cout
<< Helpers::formatstring(" End: all groups with user '%s': %s",
userName.c_str(), _ListToString(groupNames).c_str())
<< std::endl;
//-----------------------------------------------------------------
// Operation 9: Remove a user (which also removes user from all groups)
std::cout << " Operation 9: Remove a user (also removes the user from all groups)." << std::endl;
userName = "Marvin";
std::cout << Helpers::formatstring(" Removing user '%s'.", userName.c_str()) << std::endl;
mediator.RemoveUser(userName);
std::cout
<< Helpers::formatstring(" All users : %s", _ListToString(mediator.GetAllUsers()).c_str())
<< std::endl;
groupNames = mediator.GetAllGroups();
for (std::string name : groupNames)
{
userNames = mediator.GetUsersInGroup(name);
std::cout
<< Helpers::formatstring(" Users in group '%s': %s", name.c_str(), _ListToString(userNames).c_str())
<< std::endl;
}
//-----------------------------------------------------------------
std::cout << " Done." << std::endl;
}
static bool _ListToString(StringList *items, DynamicString *output)
Helper function to convert a list of strings to a comma-delimited list in a single string.
static bool Mediator_SetupUsers(void)
Helper function to add a number of users to the Users list.
static bool Mediator_SetupGroups(void)
Helper function to add a number of groups to the Groups list and then add users to the groups....
std::vector< std::string > StringList
Typedef for a vector of std::string.
std::string formatstring(const char *fmt,...)
Use the given string and arguments to return a buffer containing the formatted string....

C#

public void Run()
{
Console.WriteLine();
Console.WriteLine("Mediator Exercise");
UserGroupMediator mediator = new UserGroupMediator();
//-----------------------------------------------------------------
// Operation 1: Determine all groups
Console.WriteLine(" Operation 1: Show all groups");
Console.WriteLine(" All groups: {0}", _ListToString(mediator.GetAllGroups()));
//-----------------------------------------------------------------
// Operation 2: Determine all users
Console.WriteLine(" Operation 2: Show all users");
Console.WriteLine(" All users : {0}", _ListToString(mediator.GetAllUsers()));
//-----------------------------------------------------------------
// Operation 3: Does a user belong to a group
Console.WriteLine(" Operation 3: Determine if a user is a member of a specific group.");
string userName = "Arthur";
string groupName = "admins";
Console.Write(" Is user '{0}' in the '{1}' group?", userName, groupName);
Console.WriteLine(" {0}", mediator.IsUserInGroup(userName, groupName) ? "Yes" : "No");
//-----------------------------------------------------------------
// Operation 4: Show all users in a group
Console.WriteLine(" Operation 4: Show all users in a specific group.");
groupName = "Users";
string[] userNames = mediator.GetUsersInGroup(groupName);
Console.WriteLine(" All users in '{0}' group: {1}", groupName, _ListToString(userNames));
//-----------------------------------------------------------------
// Operation 5: Show all groups with a user
Console.WriteLine(" Operation 5: Show all groups containing a specific user.");
userName = "Marvin";
string[] groupNames = mediator.GetGroupsWithUser(userName);
Console.WriteLine(" All groups with user '{0}': {1}", userName, _ListToString(groupNames));
//-----------------------------------------------------------------
// Operation 6: Show Remove a user from a group
Console.WriteLine(" Operation 6: Remove a user from a group.");
userName = "Marvin";
groupName = "Power Users";
mediator.RemoveUserFromGroup(userName, groupName);
Console.WriteLine(" Removed user '{0}' from group '{1}'", userName, groupName);
groupNames = mediator.GetGroupsWithUser(userName);
Console.WriteLine(" All groups with user '{0}': {1}", userName, _ListToString(groupNames));
//-----------------------------------------------------------------
// Operation 7: Add a user to a group
Console.WriteLine(" Operation 7: Add a user to a group.");
groupName = "Users";
Console.WriteLine(" Adding user '{0}' to group '{1}'.", userName, groupName);
mediator.AddUserToGroup(userName, groupName);
groupNames = mediator.GetGroupsWithUser(userName);
Console.WriteLine(" All groups with user '{0}': {1}", userName, _ListToString(groupNames));
//-----------------------------------------------------------------
// Operation 8: Remove a user from all groups
Console.WriteLine(" Operation 8: Remove a user from all groups.");
userName = "Arthur";
groupNames = mediator.GetGroupsWithUser(userName);
Console.WriteLine(" Removing user '{0}' from all groups.", userName);
Console.WriteLine(" Start: all groups with user '{0}': {1}", userName, _ListToString(groupNames));
Console.WriteLine(" Removing...");
mediator.RemoveUserFromAllGroups(userName);
groupNames = mediator.GetGroupsWithUser(userName);
Console.WriteLine(" End: all groups with user '{0}': {1}", userName, _ListToString(groupNames));
//-----------------------------------------------------------------
// Operation 9: Remove a user (which also removes user from all groups)
Console.WriteLine(" Operation 9: Remove a user (also removes the user from all groups).");
userName = "Marvin";
Console.WriteLine(" Removing user '{0}'.", userName);
mediator.RemoveUser(userName);
Console.WriteLine(" All users : {0}", _ListToString(mediator.GetAllUsers()));
groupNames = mediator.GetAllGroups();
foreach (string name in groupNames)
{
userNames = mediator.GetUsersInGroup(name);
Console.WriteLine(" Users in group '{0}': {1}", name, _ListToString(userNames));
}
//-----------------------------------------------------------------
Console.WriteLine(" Done.");
}

Python

def Mediator_Exercise():
print()
print("Mediator Exercise")
mediator = UserGroupMediator()
#-----------------------------------------------------------------
# Operation 1: Determine all groups
print(" Operation 1: Show all groups")
print(" All groups: {0}".format(_ListToString(mediator.GetAllGroups())))
#-----------------------------------------------------------------
# Operation 2: Determine all users
print(" Operation 2: Show all users");
print(" All users : {0}".format(_ListToString(mediator.GetAllUsers())))
#-----------------------------------------------------------------
# Operation 3: Does a user belong to a group
print(" Operation 3: Determine if a user is a member of a specific group.");
userName = "Arthur";
groupName = "admins";
print(" Is user '{0}' in the '{1}' group?".format(userName, groupName), end="")
print(" {0}".format("Yes" if mediator.IsUserInGroup(userName, groupName) else "No"))
#-----------------------------------------------------------------
# Operation 4: Show all users in a group
print(" Operation 4: Show all users in a specific group.");
groupName = "Users";
userNames = mediator.GetUsersInGroup(groupName);
print(" All users in '{0}' group: {1}".format(groupName, _ListToString(userNames)))
#-----------------------------------------------------------------
# Operation 5: Show all groups with a user
print(" Operation 5: Show all groups containing a specific user.");
userName = "Marvin";
groupNames = mediator.GetGroupsWithUser(userName);
print(" All groups with user '{0}': {1}".format(userName, _ListToString(groupNames)))
#-----------------------------------------------------------------
# Operation 6: Show Remove a user from a group
print(" Operation 6: Remove a user from a group.");
userName = "Marvin";
groupName = "Power Users";
mediator.RemoveUserFromGroup(userName, groupName);
print(" Removed user '{0}' from group '{1}'".format(userName, groupName))
groupNames = mediator.GetGroupsWithUser(userName);
print(" All groups with user '{0}': {1}".format(userName, _ListToString(groupNames)))
#-----------------------------------------------------------------
# Operation 7: Add a user to a group
print(" Operation 7: Add a user to a group.");
groupName = "Users";
print(" Adding user '{0}' to group '{1}'.".format(userName, groupName))
mediator.AddUserToGroup(userName, groupName);
groupNames = mediator.GetGroupsWithUser(userName);
print(" All groups with user '{0}': {1}".format(userName, _ListToString(groupNames)))
#-----------------------------------------------------------------
# Operation 8: Remove a user from all groups
print(" Operation 8: Remove a user from all groups.");
userName = "Arthur";
groupNames = mediator.GetGroupsWithUser(userName);
print(" Removing user '{0}' from all groups.".format(userName))
print(" Start: all groups with user '{0}': {1}".format(userName, _ListToString(groupNames)))
print(" Removing...");
mediator.RemoveUserFromAllGroups(userName);
groupNames = mediator.GetGroupsWithUser(userName);
print(" End: all groups with user '{0}': {1}".format(userName, _ListToString(groupNames)))
#-----------------------------------------------------------------
# Operation 9: Remove a user (which also removes user from all groups)
print(" Operation 9: Remove a user (also removes the user from all groups).");
userName = "Marvin";
print(" Removing user '{0}'.".format(userName))
mediator.RemoveUser(userName);
print(" All users : {0}".format(_ListToString(mediator.GetAllUsers())))
groupNames = mediator.GetAllGroups();
for name in groupNames:
userNames = mediator.GetUsersInGroup(name);
print(" Users in group '{0}': {1}".format(name, _ListToString(userNames)))
#-----------------------------------------------------------------
print(" Done.")

C

void Mediator_Exercise(void)
{
printf("\nMediator Exercise\n");
bool canContinue = Mediator_SetupUsers();
if (canContinue)
{
canContinue = Mediator_SetupGroups();
}
if (canContinue)
{
}
if (canContinue)
{
}
if (canContinue)
{
}
if (canContinue)
{
}
if (canContinue)
{
}
if (canContinue)
{
}
if (canContinue)
{
}
if (canContinue)
{
}
if (canContinue)
{
}
//-----------------------------------------------------------------
// Clean-up
printf(" Done.\n");
}
static bool _Mediator_Example_RemoveUserFromAllGroups(void)
Helper function example of how to remove a user from all groups.
static bool _Mediator_Example_RemoveUser(void)
Helper function example of how to remove a user.
static bool _Mediator_Example_ShowAllGroupsContainingUser(void)
Helper function example of how to show all groups containing a user.
static bool _Mediator_Example_RemoveUserFromGroup(void)
Helper function example of how to remove a user from a group.
static bool _Mediator_Example_AddUserToGroup(void)
Helper function example of how to add a user to a group.
static bool _Mediator_Example_SeeIfUserInGroup(void)
Helper function example of how to see if a user is in a group.
static bool _Mediator_Example_ShowAllUsers(void)
Helper function example of how to show all users.
static bool _Mediator_Example_ShowAllGroups(void)
Helper function example of how to show all groups.
static bool _Mediator_Example_ShowUsersInGroup(void)
Helper function example of how to show all users in a group.
void Mediator_ClearAll(void)
Clear all memory associated with groups and users.

RUST

(Apologies. Doxygen does not understand Rust syntax and therefore cannot colorize the code.)

pub fn mediator_exercise() -> Result<(), String> {
println!("");
println!("Mediator Exercise");
let mut mediator = UserGroupMediator::new();
mediator_setup_users(&mut mediator);
mediator_setup_groups(&mut mediator);
//-----------------------------------------------------------------
// Operation 1: Determine all groups
println!(" Operation 1: Show all groups");
println!(" All groups: {}", list_to_string(&mediator.get_all_groups()));
//-----------------------------------------------------------------
// Operation 2: Determine all users
println!(" Operation 2: Show all users");
println!(" All users : {}", list_to_string(&mediator.get_all_users()));
//-----------------------------------------------------------------
// Operation 3: Does a user belong to a group
println!(" Operation 3: Determine if a user is a member of a specific group.");
let mut user_name = "Arthur";
let mut group_name = "admins";
let is_in_group = match mediator.is_user_in_group(user_name, group_name) {
false => "No",
true => "Yes",
};
println!(" Is user '{0}' in the '{1}' group? {2}", user_name, group_name, is_in_group);
//-----------------------------------------------------------------
// Operation 4: Show all users in a group
println!(" Operation 4: Show all users in a specific group.");
group_name = "Users";
let mut user_names = mediator.get_users_in_group(group_name);
println!(" All users in '{0}' group: {1}", group_name, list_to_string(&user_names));
//-----------------------------------------------------------------
// Operation 5: Show all groups with a user
println!(" Operation 5: Show all groups containing a specific user.");
user_name = "Marvin";
let mut group_names = mediator.get_groups_with_user(user_name);
println!(" All groups with user '{0}': {1}", user_name, list_to_string(&group_names));
//-----------------------------------------------------------------
// Operation 6: Show Remove a user from a group
println!(" Operation 6: Remove a user from a group.");
user_name = "Marvin";
group_name = "Power Users";
mediator.remove_user_from_group(user_name, group_name);
println!(" Removed user '{0}' from group '{1}'", user_name, group_name);
group_names = mediator.get_groups_with_user(user_name);
println!(" All groups with user '{0}': {1}", user_name, list_to_string(&group_names));
//-----------------------------------------------------------------
// Operation 7: Add a user to a group
println!(" Operation 7: Add a user to a group.");
group_name = "Users";
println!(" Adding user '{0}' to group '{1}'.", user_name, group_name);
mediator.add_user_to_group(user_name, group_name);
group_names = mediator.get_groups_with_user(user_name);
println!(" All groups with user '{0}': {1}", user_name,list_to_string(&group_names));
//-----------------------------------------------------------------
// Operation 8: Remove a user from all groups
println!(" Operation 8: Remove a user from all groups.");
user_name = "Arthur";
group_names = mediator.get_groups_with_user(user_name);
println!(" Removing user '{0}' from all groups.", user_name);
println!(" Start: all groups with user '{0}': {1}", user_name, list_to_string(&group_names));
println!(" Removing...");
mediator.remove_user_from_all_groups(user_name);
group_names = mediator.get_groups_with_user(user_name);
println!(" End: all groups with user '{0}': {1}", user_name, list_to_string(&group_names));
//-----------------------------------------------------------------
// Operation 9: Remove a user (which also removes user from all groups)
println!(" Operation 9: Remove a user (also removes the user from all groups).");
user_name = "Marvin";
println!(" Removing user '{0}'.", user_name);
mediator.remove_user(user_name);
println!(" All users : {0}", list_to_string(&mediator.get_all_users()));
group_names = mediator.get_all_groups();
for group_name in group_names.iter() {
user_names = mediator.get_users_in_group(&group_name);
println!(" Users in group '{0}': {1}", group_name, list_to_string(&user_names));
}
//-----------------------------------------------------------------
println!(" Done.");
Ok(())
}

See Also