Mediator Pattern in Java
Tags: java, beginners
Published: 2023-05-02 04:33:11

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

![class-diagram](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/lkvlh8cegf76q6827psd.png)

### Button
The following source code is an abstract class representing a button.
```java
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.
```java
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
```java
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
```java
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
```java
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.
```java
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.
```java
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.
```java
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

```sh
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
```sh
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
```sh
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
```sh
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
```sh
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"
```sh
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
```sh
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.