The Mediator Pattern is useful when processing needs to be performed while coordinating a large number of objects. It uses a class that acts as an "arbitrator," receiving queries from each object, making appropriate decisions, and issuing instructions.
The Mediator Pattern is commonly used in the front-end of web applications. As a rule for operating the web interface, we sometimes need to disable or enable other buttons when a certain button is clicked. To achieve this control, we prepare a class for each button. When a button is clicked, it requests processing to the other button classes. When there are multiple button classes, we need to perform processing requests for each of them.
With the Mediator Pattern, this processing can be done simply.
I have written sample code for the Mediator Pattern in Java.
JDK17
Structuring the Mediator Pattern
Button
The following source code is an abstract class representing a button.
package study.dp.mediator;
/**
* Button class:
* An abstract class for buttons A, B, and C.
* It can also be an interface, but it is expressed as an abstract class in this sample.
*/
public abstract class Button {
// Mediator
protected Mediator mediator;
// button-press-enabled flag
protected boolean enabled;
/**
* constructor
*
* @param mediator
* @param enabled
*/
public Button(Mediator mediator, boolean enabled) {
this.mediator = mediator;
this.enabled = enabled;
}
/**
* setter of 'enabled'
*
* @param enabled
*/
public void setEnabled(boolean enabled) {
this.enabled = enabled;
}
/**
* abstract method
* Describe actual processing in subclasses
*/
public abstract void press();
}
ButtonKind
Represents buttons A, B, and C.
package study.dp.mediator;
/**
* ButtonKind enum:
* Represents buttons A, B, and C.
*/
public enum ButtonKind {
A, B, C
}
Button A
Subclass of the "Button" class
package study.dp.mediator;
/**
* Button A
* Subclass of the "Button" class
*/
public class ButtonA extends Button {
private static final String MY_NAME = "Button A";
public ButtonA(Mediator mediator, boolean enabled) {
super(mediator, enabled);
}
/**
* Pressing event of button A
* Communication between objects is done through Mediator.
* In this sample code, button A only notifies Mediator and does not communicate with other buttons.
*/
@Override
public void press() {
if (this.enabled) {
// Notify Mediator
this.mediator.consulting(ButtonKind.A);
} else {
System.out.printf("%s is disabled.%n", MY_NAME);
}
}
}
Button B
Subclass of the "Button" class
package study.dp.mediator;
/**
* Button B
* Subclass of the "Button" class
*/
public class ButtonB extends Button {
private static final String MY_NAME = "Button B";
public ButtonB(Mediator mediator, boolean enabled) {
super(mediator, enabled);
}
/**
* Pressing event of button B
* Communication between objects is done through Mediator.
* In this sample code, button B only notifies Mediator and does not communicate with other buttons.
*/
@Override
public void press() {
if (this.enabled) {
// Notify Mediator
this.mediator.consulting(ButtonKind.B);
} else {
System.out.printf("%s is disabled.%n", MY_NAME);
}
}
}
Button C
Subclass of the "Button" class
package study.dp.mediator;
/**
* Button C
* Subclass of the "Button" class
*/
public class ButtonC extends Button {
private static final String MY_NAME = "Button C";
public ButtonC(Mediator mediator, boolean enabled) {
super(mediator, enabled);
}
/**
* Pressing event of button C
* Communication between objects is done through Mediator.
* In this sample code, button C only notifies Mediator and does not communicate with other buttons.
*/
@Override
public void press() {
if (this.enabled) {
// Notify Mediator
this.mediator.consulting(ButtonKind.C);
} else {
System.out.printf("%s is disabled.%n", MY_NAME);
}
}
}
Mediator
This is an interface representing the mediator. It prepares methods to receive consultations from each button.
package study.dp.mediator;
/**
* Mediator interface:
* An interface for the mediator.
* It prepares a code value when each button is pressed
* and a method to receive consultation from each button.
*/
public interface Mediator {
// Methods to be consulted from each button
void consulting(ButtonKind buttonKind);
}
Web Screen
This class implements the "mediator" and represents the web page.
package study.dp.mediator;
/**
* A class that represents a web screen.
* It has buttons A, B, and C on the screen.
* When a button is pressed, it becomes unpressable,
* and the other buttons become pressable according to a certain rule.
*/
public class WebScreen implements Mediator {
private final ButtonA buttonA;
private final ButtonB buttonB;
private final ButtonC buttonC;
public WebScreen() {
// ButtonA and ButtonB is enabled. ButtonC is disabled.
buttonA = new ButtonA(this, true);
buttonB = new ButtonB(this, true);
buttonC = new ButtonC(this, false);
}
public ButtonA getButtonA() {
return buttonA;
}
public ButtonB getButtonB() {
return buttonB;
}
public ButtonC getButtonC() {
return buttonC;
}
/**
* Overridden method of Mediator interface.
* This method is called when each button is clicked.
* As each button's press control and message processing are performed in this method,
* each button no longer needs to be aware of the other buttons.
* This reduces object dependency and coupling.
*
* @param buttonKind Buttons A, B, C
*/
@Override
public void consulting(ButtonKind buttonKind) {
switch (buttonKind) {
case A:
System.out.println("Button A is pressed. Button A is disabled. \"Button B\" and \"Button C\" is enabled.");
// ButtonA is disabled.
this.buttonA.setEnabled(false);
// ButtonB is enabled.
this.buttonB.setEnabled(true);
// ButtonC is enabled.
this.buttonC.setEnabled(true);
break;
case B:
System.out.println("Button B is pressed. Button B is disabled. \"Button A\" and \"Button C\" is enabled.");
// ButtonB is disabled.
this.buttonB.setEnabled(false);
// ButtonA is enabled.
this.buttonA.setEnabled(true);
// ButtonC is enabled.
this.buttonC.setEnabled(true);
break;
case C:
System.out.println("Button C is pressed. Button C is disabled. \"Button A\" and \"Button B\" is enabled.");
// ButtonC is disabled.
this.buttonC.setEnabled(false);
// ButtonA is enabled.
this.buttonA.setEnabled(true);
// ButtonB is enabled.
this.buttonB.setEnabled(true);
break;
default:
break;
}
}
/**
* Overridden method of Object class.
* A method that can be overridden in all classes.
* Override toString method to return information about the class in String format.
* In this sample, it returns information about the pressability status of buttons A, B, and C.
*
* @return Information on the web screen. Pressable status of buttons A, B, and C
*/
@Override
public String toString() {
String ret = "There are buttons A, B, and C on the screen.\n";
ret += "Please push the key. ";
if (this.buttonA.enabled) {
ret += "A: Button A, ";
}
if (this.buttonB.enabled) {
ret += "B: Button B, ";
}
if (this.buttonC.enabled) {
ret += "C: Button C, ";
}
ret += "E: End";
return ret;
}
}
Main
We create a Main class to move the web page. In the Main class, we enable console input to specify which button to press.
package study.dp.mediator;
import java.util.Scanner;
/**
* Main class:
* The main class that runs the sample application.
* It can input button names on the console.
* It displays the result of the Mediator on the screen.
*/
public class Main {
public static void main(String[] args) {
WebScreen webScreen = new WebScreen();
boolean play = true;
while (play) {
System.out.println(webScreen);
// Create an instance of the Scanner class.
Scanner sc = new Scanner(System.in);
// Retrieve input from the console.
String input = sc.nextLine();
switch (input) {
case "A":
// Input value: A
webScreen.getButtonA().press();
break;
case "B":
// Input value: B
webScreen.getButtonB().press();
break;
case "C":
// Input value: C
webScreen.getButtonC().press();
break;
case "E":
// Input value: E
play = false;
System.out.println("Processing has been terminated.");
break;
default:
System.out.println("input error.");
break;
}
}
}
}
Execution result
I entered text into the console and pressed Enter to confirm the operation. The results of the execution are as follows:
1.Initial display
There are buttons A, B, and C on the screen.
Please push the key. A: Button A, B: Button B, E: End
2.Result of entering the "A" key
There are buttons A, B, and C on the screen.
Please push the key. A: Button A, B: Button B, E: End
A
Button A is pressed. Button A is disabled. "Button B" and "Button C" is enabled.
There are buttons A, B, and C on the screen.
Please push the key. B: Button B, C: Button C, E: End
3.Result of entering the "A" key again
There are buttons A, B, and C on the screen.
Please push the key. B: Button B, C: Button C, E: End
A
Button A is disabled.
There are buttons A, B, and C on the screen.
Please push the key. B: Button B, C: Button C, E: End
4.Result of entering the "B" key
There are buttons A, B, and C on the screen.
Please push the key. B: Button B, C: Button C, E: End
B
Button B is pressed. Button B is disabled. "Button A" and "Button C" is enabled.
There are buttons A, B, and C on the screen.
Please push the key. A: Button A, C: Button C, E: End
5.Result of entering the "C" key
There are buttons A, B, and C on the screen.
Please push the key. A: Button A, C: Button C, E: End
C
Button C is pressed. Button C is disabled. "Button A" and "Button B" is enabled.
There are buttons A, B, and C on the screen.
Please push the key. A: Button A, B: Button B, E: End
6.Result of entering "aaa"
There are buttons A, B, and C on the screen.
Please push the key. A: Button A, B: Button B, E: End
aaa
input error.
There are buttons A, B, and C on the screen.
Please push the key. A: Button A, B: Button B, E: End
7.Result of entering the "E" key
There are buttons A, B, and C on the screen.
Please push the key. A: Button A, B: Button B, E: End
E
Processing has been terminated.
Summary
When multiple object classes exist and are related to each other, the Mediator pattern takes over their control. This can eliminate the relationships between objects and increase reusability.
Using the Mediator pattern, communication between objects is encapsulated by the mediator, allowing for a reduction in the dependency and coupling between the communicating objects, as they no longer directly communicate with each other but instead through the mediator.
Top comments (3)
Hey there, thanks for sharing your post with the community! I really appreciate the effort you put into it. I noticed that you included some code snippets, but it would be really helpful if you could add some explanations or comments to them. While a seasoned developer might be able to understand the code, newer members might find it a bit challenging, especially since you used the beginners tag. Adding some explanations or comments would make it a lot easier for everyone to follow along and learn from your post. Thanks again for sharing, and I look forward to seeing more of your contributions in the future!
Hello there,
Thank you so much for taking the time to read my article and leave a comment, I really appreciate it! I apologize for not providing enough explanations for the code snippets in my post. I have now revised the code explanations and added more details, so I hope that it is easier to understand, especially for newer members.
I'm really glad to hear that you found my article helpful and I will definitely keep your feedback in mind for my next post. I'm planning to include more diagrams and explanations to make my content even more accessible and easier to understand.
Once again, thank you for your feedback, and I hope that my updated post meets your expectations. Looking forward to sharing more content with you in the future!
Best regards,
Thank you so much for your comment! Your effort to revise your code explanations and add more details is truly appreciated. It's not that your post didn't meet my personal expectations per se, but rather that I believe it will benefit the community as a whole. Your dedication to improving the accessibility of your content for newer members is commendable, and I'm sure that many readers will find your revised explanations helpful. Keep up the great work and I'm excited to read more of your content in the future!