Core Java

Mediator Design Pattern In Java

In this tutorial, we’ll learn about a behavioral pattern that promotes loose coupling between several objects communicating with one another. The idea behind the Mediator design pattern is to have a central object that encapsulates how a set of objects interact.

In the mediator pattern, we extract all the relationships between different classes in a separate class known as a mediator. This enables us to make changes to one component without impacting the entire system.

And so, we have a more loosely-coupled system that’s easier to extend and maintain.

UML Representation:

We can represent the mediator pattern with the help of following UML diagram:

Here, we have:

  • Mediator: an interface or an abstract class defining the contract for communication among colleagues
  • ConcreteMediator: a class that implements the mediator contract; it is aware of all colleagues and their inter-communications. Any communication among colleagues happens only through a mediator
  • Colleague: an interface or an abstract class representing components of our system
  • ConcreteColleague: classes that implement the Colleague interface and are willing to interact with one another

Implementing the Mediator Pattern:

Let’s take the example of an aerospace traffic control system.

Each flight needs to know about the available runway for its landing. If we allow inter-communication among the aircraft for them to find the available runway, it will lead to chaos. Rather, it’s a good idea to have an aircraft traffic control room which keeps track of all available runways and assigns them to an aircraft.

Let’s start by defining an AircraftMediator and the AircraftTrafficControlRoom:

public interface AircraftMediator {
 
    public void registerRunway(Runway runway);
    public String allotRunwayTo(Aircraft aircraft);    
    public void releaseRunwayOccupiedBy(Aircraft aircraft); 
}
 
public class AicraftTrafficControlRoom implements AircraftMediator {
    
    private LinkedList<Runway> availableRunways = new LinkedList<>(); 
    private Map<Aircraft, Runway> aircraftRunwayMap = new HashMap<>();
 
    @Override
    public void registerRunway(Runway runway) {
        this.availableRunways.add(runway);
    }
 
    @Override
    public String allotRunwayTo(Aircraft aircraft) {
        Runway nextAvailbleRunway = null;
        if(!this.availableRunways.isEmpty()) {
            nextAvailbleRunway = this.availableRunways.removeFirst();
            this.aircraftRunwayMap.put(aircraft, runway);
        }
        return nextAvailbleRunway == null ? 
          null : nextAvailbleRunway.getName();
    }
 
    @Override
    public void releaseRunwayOccupiedBy(Aircraft aircraft) {
        if(this.aircraftRunwayMap.containsKey(aircraft)) {
            Runway runway = this.aircraftRunwayMap.remove(aircraft);
            this.availableRunways.add(runway); 
        }
    }
}

The air traffic control room acts as a mediator and keeps track of all available runways. It’s responsible to allot and release runways.

Defining Colleagues:

Now, let’s define our Aircraft, the instances of which will be the colleagues:

public interface AircraftColleague {
    void startLanding();
    void finishLanding();
}
 
public class Aircraft implements AircraftColleague {
 
    private AircraftMediator mediator;
    private String flightName;
 
    public Aircraft(AircraftMediator mediator, String flightName) {
        this.mediator = mediator;
        this.flightName = flightName;
    }
 
    @Override
    public void startLanding() {
        String runway = this.mediator.allotRunwayTo(this);
        if(runway == null) {
            //informing passengers
            System.out.println("Due to traffic, there's a delay in landing of " + this.flightName );  
        } else {
            System.out.println("Currently landing " + this.flightName + " on " + runway);  
        }  
    }
 
    @Override
    public void finishLanding() {
       System.out.println(this.flightName + "landed successfully");
       this.mediator.releaseRunwayOccupiedBy(this);
    }
}

Testing Our Implementation:

Let’s see how this works together:

// In our main method
Runway runwayA = new Runway("Runway A");
 
AircraftMediator mediator = new AircraftTrafficControlRoom();
mediator.registerRunway(runwayA);
 
AircraftColleague wrightFlight = new Aircraft(mediator, "Wright Flight"); 
AircraftColleague airbusA380 = new Aircraft(mediator, "Airbus A380"); 
 
wrightFlight.startLanding(); 
airbusA380.startLanding();
wrightFlight.finishLanding(); 

On executing the above code, we’ll have the following output:

Currently landing Wright Flight on Runway A
Due to traffic, there's a delay in landing of Airbus A380
Wright Flight landed successfully

If we again attempt a landing of the airbus, we’ll be able to proceed with it as the runway is now available.

Conclusion:

In this tutorial, we learned how to implement a mediator pattern. We’ll use a mediator pattern when we have a system in which multiple objects communicate with each other. This pattern promotes loose coupling and thereby makes the system more flexible.

A common application of this pattern is a chat or messaging system. Moreover, the Java Concurrency Executor’s execute() method makes use of this pattern.

Published on Java Code Geeks with permission by Shubhra Srivastava, partner at our JCG program. See the original article here: Mediator Design Pattern In Java

Opinions expressed by Java Code Geeks contributors are their own.

Shubhra Srivastava

Shubhra is a software professional and founder of ProgrammerGirl. She has a great experience with Java/J2EE technologies and frameworks. She loves the amalgam of programming and coffee :)
Subscribe
Notify of
guest

This site uses Akismet to reduce spam. Learn how your comment data is processed.

2 Comments
Oldest
Newest Most Voted
Inline Feedbacks
View all comments
Rahul Singh Bhandari
Rahul Singh Bhandari
4 years ago

1-) Please add Runaway and Aircraft classes.
2-) Replace : allotRunaway() – this.aircraftRunwayMap.put(aircraft, runway) with this.aircraftRunwayMap.put(aircraft,nextAvailbleRunway);

Oran1980
Oran1980
2 years ago

Hi,
in the below method, (in the marked line, where added the pair to the map), shouldn’t the ‘runway’ be replaced with ‘nextAvailableRunway’?

@Override
    

public

String allotRunwayTo(Aircraft aircraft) {
        

Runway nextAvailbleRunway =

null

;
        

if

(!

this

.availableRunways.isEmpty()) {
            

nextAvailbleRunway =

this

.availableRunways.removeFirst();
            

this

.aircraftRunwayMap.put(aircraft, runway);
        

}
        

return

nextAvailbleRunway ==

null

?
          

null

: nextAvailbleRunway.getName();
    

}

Back to top button