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:
- Determine all groups available
- Determine all users available
- Determine if a particular user belongs to a particular group
- Determine all users that are in a particular group
- Determine all groups that contain a particular user
- Remove a particular user from a particular group
- Add a particular user to a particular group
- remove a particular user from all groups
- Remove a user, which entails removing the user from all groups
- Add a new group
- remove a group
- 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
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:
{
public string Name {
get; }
}
{
public string Name {
get; }
public bool ContainsUser(string name);
public void AddUser(string name);
public void RemoveUser(string name);
}
{
public User FindUser(
string name);
public void AddUser(string name);
public void RemoveUser(string name);
}
{
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.
const char * Name
The name of the user.
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;
std::cout << " Operation 1: Show all groups" << std::endl;
std::cout
<< std::endl;
std::cout << " Operation 2: Show all users" << std::endl;
std::cout
<< std::endl;
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";
userName.c_str(), groupName.c_str());
std::cout
<< std::endl;
std::cout << " Operation 4: Show all users in a specific group." << std::endl;
groupName = "Users";
StringList userNames = mediator.GetUsersInGroup(groupName);
std::cout
<< std::endl;
std::cout << " Operation 5: Show all groups containing a specific user." << std::endl;
userName = "Marvin";
StringList groupNames = mediator.GetGroupsWithUser(userName);
std::cout
<< std::endl;
std::cout << " Operation 6: Remove a user from a group." << std::endl;
userName = "Marvin";
groupName = "Power Users";
mediator.RemoveUserFromGroup(userName, groupName);
userName.c_str(), groupName.c_str()) << std::endl;
groupNames = mediator.GetGroupsWithUser(userName);
std::cout
<< std::endl;
std::cout << " Operation 7: Add a user to a group." << std::endl;
groupName = "Users";
userName.c_str(), groupName.c_str())
<< std::endl;
mediator.AddUserToGroup(userName, groupName);
groupNames = mediator.GetGroupsWithUser(userName);
std::cout
<< std::endl;
std::cout << " Operation 8: Remove a user from all groups." << std::endl;
userName = "Arthur";
groupNames = mediator.GetGroupsWithUser(userName);
userName.c_str())
<< std::endl;
std::cout
<< std::endl;
std::cout << " Removing..." << std::endl;
mediator.RemoveUserFromAllGroups(userName);
groupNames = mediator.GetGroupsWithUser(userName);
std::cout
<< std::endl;
std::cout << " Operation 9: Remove a user (also removes the user from all groups)." << std::endl;
userName = "Marvin";
mediator.RemoveUser(userName);
std::cout
<< std::endl;
groupNames = mediator.GetAllGroups();
for (std::string name : groupNames)
{
userNames = mediator.GetUsersInGroup(name);
std::cout
<< std::endl;
}
std::cout << " Done." << std::endl;
}
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();
Console.WriteLine(" Operation 1: Show all groups");
Console.WriteLine(
" All groups: {0}",
_ListToString(mediator.GetAllGroups()));
Console.WriteLine(" Operation 2: Show all users");
Console.WriteLine(
" All users : {0}",
_ListToString(mediator.GetAllUsers()));
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");
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));
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));
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));
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));
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));
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()
print(" Operation 1: Show all groups")
print(
" All groups: {0}".format(
_ListToString(mediator.GetAllGroups())))
print(" Operation 2: Show all users");
print(
" All users : {0}".format(
_ListToString(mediator.GetAllUsers())))
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"))
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)))
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)))
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)))
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)))
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)))
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");
if (canContinue)
{
}
if (canContinue)
{
}
if (canContinue)
{
}
if (canContinue)
{
}
if (canContinue)
{
}
if (canContinue)
{
}
if (canContinue)
{
}
if (canContinue)
{
}
if (canContinue)
{
}
if (canContinue)
{
}
printf(" Done.\n");
}
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