Mediator Design Pattern: Sometimes we need a mechanism to facilitate the interaction between objects in a manner in that objects are not aware of the existence of other objects. In other words Mediator helps in achieving loose coupling between various objects by keeping objects from referring to each other explicitly, and it makes their interaction independent.
There are some point which we need to keep in mind while choosing this design pattern.
- Mediator pattern helps to achieve loose coupling.
- You should know if there is a coupling between the components, in you code
- Once you identified the coupling between the components, you can think of using this design pattern.
I will explain it with example how you can decouple your various components from each other with help of a Mediator. Mediator provides us the freedom to do modification in any component without touching other components.
Lets take an example: You want to design a UI Screen which will have many components to display. And on click of a button in one component, other components have to be updated, Components can update their texts, data models and views based on the functional requirement.
For more clarity lets suppose a screen has five components, and these components are added in screen at Left, Right, Top, Bottom and Center as shown in the below image.
Actions: On each button click all five/four Components need to update their view and data accordingly.
There are multiple ways to do this.
- One way of doing this is create a MainScreen class and in this class create all buttons, labels etc add all these components to the main screen. On click of each button update all components data and view using their object instances as set model and set text etc.
- If the screen has a status bar the you need to create its components in main screen. Then you need to set Status bar text using one of its component instance like statusLabel.setText("message").
The problem in this approach is all the components are tightly coupled with each other. So if you want to change any component then you have to change lots of code in MainScreen. for example if I want to replace component-4 with some new component then it is difficult to do.
So to avoid high coupling we can use Mediator design pattern, which make your code less coupled and each component can be modified independently. Means change in one component will not affect other component in any way.
Let see how to achieve this and how to implements design patterns.
Create Component-1, let name it as TopComponent class, and add the UI buttons, text fields and required items to it. TopComponent class extends JPanel and implements ActionListener to handle buttons click as below.
public class TopComponent extends JPanel implements ActionListener{
private JButton button1;
public TopComponent (){//constructor
createUI();
}
private void createUI(){
//create your items ,label and other UI components as required and add
button1 = new JButton("Button1");
button1.addActionListener(this);
add(button1);
}
public void actionPerformed(ActionEvent e){
if(e.getSource() == button1){
//do the task as required
}
}
}//end class
private JButton button1;
public TopComponent (){//constructor
createUI();
}
private void createUI(){
//create your items ,label and other UI components as required and add
button1 = new JButton("Button1");
button1.addActionListener(this);
add(button1);
}
public void actionPerformed(ActionEvent e){
if(e.getSource() == button1){
//do the task as required
}
}
}//end class
Same way create Component-2 , Component-3, Component-4 and Component-5 classes as LeftComponet CenterComponent, RightComponent and BottomComponent.
Now we will apply the mediator design pattern and change these classes accordingly. To do this we can follow these steps
- Create a class UpdateEvent.
- Create an interface ComponentView.
- Create a class Mediator.
- Update components and MainScreen class for mediator related changes.
UpdateEvent .java
public class UpdateEvent {
public static final int UPDATE = 0;
public static final int SHOW = 1;
public static final int HIDE = 2;
public static final int LOAD = 3;
private int eventType = -1;
public UpdateEvent (int eventType){
this.eventType = eventType ;
}
public int getEventType(){
return eventType;
}
}//end class
public static final int UPDATE = 0;
public static final int SHOW = 1;
public static final int HIDE = 2;
public static final int LOAD = 3;
private int eventType = -1;
public UpdateEvent (int eventType){
this.eventType = eventType ;
}
public int getEventType(){
return eventType;
}
}//end class
Create an interface ComponentView as shown here
ComponentView.java
public interface ComponentView{
updateView(UpdateEvent e);
}//end interface
updateView(UpdateEvent e);
}//end interface
Create a Mediator class as following
Mediator.java
public class Mediator{
// array list which will hold the reference of all components and will interact with each other.
private ArrayList<ComponentView> componentViews = new ArrayList<ComponentView>();
public void register(ComponentView view){
componentViews .add(view);
}
public void fireUpdate(UpdateEvent e){
// mediator will send this event to all other components, only interested components will handle it.
for(int i=0; i< componentViews.size(); i++){
ComponentView view = componentViews.get(i);
view.updateViwe (e);
}
}
}//end class
// array list which will hold the reference of all components and will interact with each other.
private ArrayList<ComponentView> componentViews = new ArrayList<ComponentView>();
public void register(ComponentView view){
componentViews .add(view);
}
public void fireUpdate(UpdateEvent e){
// mediator will send this event to all other components, only interested components will handle it.
for(int i=0; i< componentViews.size(); i++){
ComponentView view = componentViews.get(i);
view.updateViwe (e);
}
}
}//end class
Now we will modify all the Component-1,2,3,4 and Component-5 classes as following
TopComponent.java
public class TopComponent extends JPanel implements ActionListener, ComponentView{
private JButton button1;
private Mediator mediator;
public TopComponent (Mediator mediator){//constructor
this.mediator = mediator;
this.mediator.register(this);
createUI();
}
private void createUI(){
//create your items ,label and other UI components as required and add
button1 = new JButton("Button1");
button1.addActionListener(this);
add(button1);
}
public void actionPerformed(ActionEvent e){
if(e.getSource() == button1){
//do the task as required
mediator.fireUpdate(new UpdateEvent(UpdateEvent.UPDATE ));
//This will send the update event to the mediator, and mediator will send
// this event to all other components.
}
}
//this component will only interested in LOAD event sent by other component so handle it here
public void updateView(UpdateEvent e){
if(e.getEventType() == UpdateEvent.LOAD){
// load the data and update the view accordingly
}
}
}//end class
private JButton button1;
private Mediator mediator;
public TopComponent (Mediator mediator){//constructor
this.mediator = mediator;
this.mediator.register(this);
createUI();
}
private void createUI(){
//create your items ,label and other UI components as required and add
button1 = new JButton("Button1");
button1.addActionListener(this);
add(button1);
}
public void actionPerformed(ActionEvent e){
if(e.getSource() == button1){
//do the task as required
mediator.fireUpdate(new UpdateEvent(UpdateEvent.UPDATE ));
//This will send the update event to the mediator, and mediator will send
// this event to all other components.
}
}
//this component will only interested in LOAD event sent by other component so handle it here
public void updateView(UpdateEvent e){
if(e.getEventType() == UpdateEvent.LOAD){
// load the data and update the view accordingly
}
}
}//end class
LeftComponent.java
public class LeftComponent extends JPanel implements ActionListener, ComponentView{
private JButton button1;
private JButton button2;
private Mediator mediator;// keep an instance of mediator
public LeftComponent (Mediator mediator){//constructor
this.mediator = mediator;
this.mediator.register(this);
createUI();
}
private void createUI(){
//create your items ,label and other UI components as required and add
button1 = new JButton("Button1");
button1.addActionListener(this);
add(button1);
}
public void actionPerformed(ActionEvent e){
//This will send the load event to the mediator, and mediator will send
// this event to all other components.
if(e.getSource() == button1){
//do the task as required
mediator.fireUpdate(new UpdateEvent(UpdateEvent.HIDE));
//this will make other components to hide some info if needed
}else if(e.getSource() == button2){
//do the task as required
mediator.fireUpdate(new UpdateEvent(UpdateEvent.LOAD));
//this will make other components to Load data again if needed
}
}
//this component will only interested in UPDATE event so handle it here
public void updateView(UpdateEvent e){
if(e.getEventType() == UpdateEvent.UPDATE){
// update the view accordingly
}
}
}//end class
private JButton button1;
private JButton button2;
private Mediator mediator;// keep an instance of mediator
public LeftComponent (Mediator mediator){//constructor
this.mediator = mediator;
this.mediator.register(this);
createUI();
}
private void createUI(){
//create your items ,label and other UI components as required and add
button1 = new JButton("Button1");
button1.addActionListener(this);
add(button1);
}
public void actionPerformed(ActionEvent e){
//This will send the load event to the mediator, and mediator will send
// this event to all other components.
if(e.getSource() == button1){
//do the task as required
mediator.fireUpdate(new UpdateEvent(UpdateEvent.HIDE));
//this will make other components to hide some info if needed
}else if(e.getSource() == button2){
//do the task as required
mediator.fireUpdate(new UpdateEvent(UpdateEvent.LOAD));
//this will make other components to Load data again if needed
}
}
//this component will only interested in UPDATE event so handle it here
public void updateView(UpdateEvent e){
if(e.getEventType() == UpdateEvent.UPDATE){
// update the view accordingly
}
}
}//end class
Similarly we can modify other components classes.
MainScreen.java
class MainScreen extends JFrame{
private Mediator mediator;
MainScreen (){
super();
mediator = new Mediator();
}
public void createUI(){
//Create all your components here and add to the main screen
TopComponent component1 = new TopComponent(mediator );
LeftComponent component2 = new LeftComponent(mediator );
CenterComponent component3 = new CenterComponent(mediator );
RightComponent component4 = new RightComponent (mediator );
BottomComponent component5 = new BottomComponent(mediator );//status bar
getContentPane().add(component1, BorderLayout.PAGE_START);
getContentPane().add(component2, BorderLayout.LINE_START);
getContentPane().add(component3, BorderLayout.CENTER);
getContentPane().add(component4, BorderLayout.LINE_END);
getContentPane().add(component5, BorderLayout.PAGE_END);
}
public static void main(String[] arg){
MainScreen mainScreen = new MainScreen ();
mainScreen.createUI();
mainScreen.setVisible(true);
}
}//end class
private Mediator mediator;
MainScreen (){
super();
mediator = new Mediator();
}
public void createUI(){
//Create all your components here and add to the main screen
TopComponent component1 = new TopComponent(mediator );
LeftComponent component2 = new LeftComponent(mediator );
CenterComponent component3 = new CenterComponent(mediator );
RightComponent component4 = new RightComponent (mediator );
BottomComponent component5 = new BottomComponent(mediator );//status bar
getContentPane().add(component1, BorderLayout.PAGE_START);
getContentPane().add(component2, BorderLayout.LINE_START);
getContentPane().add(component3, BorderLayout.CENTER);
getContentPane().add(component4, BorderLayout.LINE_END);
getContentPane().add(component5, BorderLayout.PAGE_END);
}
public static void main(String[] arg){
MainScreen mainScreen = new MainScreen ();
mainScreen.createUI();
mainScreen.setVisible(true);
}
}//end class
In this approach if you want to replace any component with some other component then you only need to change the file lines of code as shown here.
Let say you want to replace RightComponent to some NewComponent then you just need to change the code as :
// RightComponent component4 = new RightComponent (mediator );
NewComponent component4 = new NewComponent (mediator );
That's it you are done. No need to touch any other component code.
Mediator pattern is best suited for distributed modules or systems, Let see one example.
Problem |
Here module A and module B are interacting with each other, and module A knows about module B (means A need to have an instance of module B). Same way Module B knows about module A, since on some activity in module A, module B needs to be updated and vice versa.
So here both module A and B are tightly coupled with each other.
Solution : Coupling between module A and module B can be removed easily by introducing a Mediator here as A--M--B. shown in below image.
Solution
Now module A even dose not know that there is any module B exist or not.
No comments :
Post a Comment