Introduction to Mediator Pattern

In this article we are going to learn about Mediator Pattern. What is Mediator? What are the basic principle? How we can implement and where we can implement?
In the example, I am using Java in Eclipse and C# in VS2010.

What is Mediator?
In OO design, when we get a lot of object interacting each other and in final outcomes, it may create a mess up among tight couple classes. In order to avoid tight coupled framework, Mediator pattern helps us to provide the interaction between objects in a manner that objects are not aware of existence of other objects.

Lets think a gird view where each row representing objects. If we press the sorting option in the top of the grid, each object have to interact to each other for sorting comparison. Mediator makes an unique way to do that without informing any object about other object's presence.

Or, let's think about another simple example. Remember , in school days, students used to make a Line for morning assembly. Suppose each student as object. And it is really hard to make all student in a line , spatially for the primary section students. Now, if a teacher makes all students in a line and each student just follow teacher's instruction (not to talk to others) then The teacher acts as Mediator.

In summary , we can say, mediator pattern is used to handle communication between related objects.

Basic Principles :
- Moderator defines how a set of (related)objects will interact
- Mediator keeps loose coupling among the objects for referring each other explicitly.
- It also let us implement interaction vary(changeable) among objects.

UML :

How to implement?
Let's think how to implement. In here, we have manly 2 acting roles.
1. Objects which are related to each other and have to perform interaction to each other. These are called colleagues.
2. A central object which will manage the interaction among those objects. This is call mediator. Usually a mediator is defined for a one or more purposes. They contains basic interaction functions which will be defined in Interface/abstract class that those colleagues will use.

And, we can also define a abstract colleague class which may contain interaction definitions sharable among colleagues. So, finally we need
1. Mediator Interface
2. Mediator Implementing real mediator
3. Colleague abstract class
4. Colleague implementing classes.

Let's see more details with example ;

Example : Lets think of a software company. Suppose, in a company we have 3 kind of resources. Developers, Testers and Administrator. They are experienced and company make a program where each type of resources can get together for knowledge exchange. As, we know, mediator pattern helps in communication among same type object with their common functionality(all are colleagues) so, we apply mediator here. That means, we will have
1. Exchanging object which is knowledge
2. Colleague objects which are Developers, Testers & Administrators
3. A mediator class who contains every scopes among them and performs interactions/communication.
So, what they Exchange , Knowledge. Let's make a knowledge class contains subject name, how long it will take and employee id(employee code) for pointing who will actually have that knowledge.
public class Knowledge {
    private String subject="Not Selected";
    private int hour=0;
    private int employeeCode=0;
    public Knowledge(String sub, int hr, int code){
        subject=sub;
        hour = hr;
        employeeCode=code;
    }
    public String getSubject() {
        return subject;
    }
    public int getHour() {
        return hour;
    }
    public int getEmployeeCode() {
        return employeeCode;
    }
}

And, we have Employee(as colleague) who will interact among them selves. So, lets define interaction behaviors and adding colleague(in the example, Employee) in interface that actually defines the behaviors (give knowledge and get knowledge)


public interface IMediator {
    public void giveKnowledge(String subject, int hour,int employeeCode);
    public void getKnowledge(String subject, int hour,int employeeCode);
    public void addEmployee(Employee employee);
}

In here, we see addEmployee  calls colleague class(Employee) . And now, we define the abstract class Employee which is working as colleague. 


public abstract class Employee {
    private IMediator mediator;
    private int employeeCode = 0;
    public Employee(IMediator aMeadiator){
        mediator=aMeadiator;
        mediator.addEmployee(this);
    }    
    public void teachingOffer(String subject, int time) {//Teaches
        mediator.giveKnowledge(subject, time, employeeCode);
    }
    public void learningRequests(String subject, int time) {//learns
        mediator.getKnowledge(subject, time, employeeCode);
    }
    public void setEmployeeCode(int code){
        employeeCode=code;
    }
}

So, lets define 3 kinds of employee Developer, Tester, Administrators who extends Employee


public class Administrators extends Employee{
    public Administrators(IMediator aMeadiator) {
        super(aMeadiator);
        System.out.println("Administrators have signed up for schooling \n");
    }
}
public class Developer extends Employee{
    public Developer(IMediator aMeadiator) {
        super(aMeadiator);
        System.out.println("Developers have signed up for schooling \n");
    }
}
public class Testers extends Employee{
    public Testers(IMediator aMeadiator) {
        super(aMeadiator);
        System.out.println("Testers have signed up for schooling \n");
    }
}

Now, the main collaborator or the mediator(who implements the IMediator). Lets call it Schooling Mediator.
(A mediator who manage schooling and stores every possible transaction inside of it)


public class SchoolingMediator implements IMediator {
    private ArrayList<Knowledge> allTeachingOffers = null;
    private ArrayList<Knowledge> alllearningRequests = null;
    private ArrayList<Employee> allEmployees = null;
    private int employeeCode = 0;
    public SchoolingMediator(){
        allTeachingOffers = new ArrayList<Knowledge>();
        alllearningRequests = new ArrayList<Knowledge>();
        allEmployees = new ArrayList<Employee>();        
    }    
    public void addEmployee(Employee employee) {
        allEmployees.add(employee);
        employeeCode++;
        employee.setEmployeeCode(employeeCode);
    }
    public void getAllTrainings(){
        System.out.println("\nThese are Teaching Offers ");
        for(Knowledge aKnolwdge : allTeachingOffers){
            System.out.println(aKnolwdge.getSubject()+" for "+aKnolwdge.getHour()+" Hrs");
        }
        System.out.println("\nThese are learning Requests ");
        for(Knowledge aKnolwdge : alllearningRequests){
            System.out.println(aKnolwdge.getSubject()+" for "+aKnolwdge.getHour()+" Hrs");
        }
    }
    public void giveKnowledge(String subject, int hour, int employeeCode) {
        boolean knowledgeGiven = false;
        for(Knowledge aTeachingingSubject:alllearningRequests){
            //now, we check if requested learning subject and hour matches any of available Teaching subject and hour
            if(aTeachingingSubject.getSubject()==subject&&aTeachingingSubject.getHour()==hour){
                System.out.println("\n"+hour+" hour(s) subject \""+subject+"\" is taught by ID "+employeeCode+" , and learned by id "+aTeachingingSubject.getEmployeeCode());
                alllearningRequests.remove(aTeachingingSubject);//removing learned subject
                knowledgeGiven=true;
            }
            if(knowledgeGiven){//if any one give the knowledge
                break;
            }
        }
        if(!knowledgeGiven){//if no knowledge is given , it will be added in Teaching offers
            System.out.println(subject+" is added in the Teaching offers and time(hrs) is "+hour);
            allTeachingOffers.add(new Knowledge(subject, hour, employeeCode));
        }                
    }    
    public void getKnowledge(String subject, int hour, int employeeCode) {
        boolean knowledgeLearn = false;
        for(Knowledge aLearningSubject:allTeachingOffers){
            //now, we check if requested learning subject and hour matches any of available Teaching subject and hour
            if(aLearningSubject.getSubject()==subject&&aLearningSubject.getHour()==hour){
                System.out.println("\n"+hour+" hour(s) subject \""+subject+"\" is learned by ID "+employeeCode+" , and taught by id "+aLearningSubject.getEmployeeCode());
                allTeachingOffers.remove(aLearningSubject);//removing learned subject
                knowledgeLearn=true;
            }
            if(knowledgeLearn){//if any one get the knowledge
                break;
            }
        }
        if(!knowledgeLearn){//if no knowledge is delivered , it will be added in learning requests.
            System.out.println(subject+" is added in the learning requests and time(hrs) is "+hour);
            alllearningRequests.add(new Knowledge(subject, hour, employeeCode));
        }        
    }
}

Now, make a scenario in the main program.


public class Program {
    public static void main(String[] args) {
        SchoolingMediator kazSchool = new SchoolingMediator();
        Developer myDevs = new Developer(kazSchool);
        Testers myTesters = new Testers(kazSchool);
        Administrators myAdmins = new Administrators(kazSchool);        
        myDevs.learningRequests("QTP", 5);//learning qtp for 5 hours
        myDevs.learningRequests("SVN Administration", 2);//learning SVN administration for 2 hours
        myDevs.teachingOffer("Unit Testing", 1);
        myDevs.teachingOffer("Java", 20);
        myDevs.teachingOffer("c#", 20);        
        myTesters.learningRequests("Java", 20);
        myTesters.learningRequests("c#", 10);
        myTesters.teachingOffer("QTP", 5);
        myTesters.teachingOffer("Selenium", 5);
        myTesters.teachingOffer("Session Hacking", 5);        
        myAdmins.learningRequests("Session Hacking", 5);
        myAdmins.learningRequests("Unit Testing", 1);
        myAdmins.teachingOffer("SVN Administration", 2);
        myAdmins.teachingOffer("Linux Administration", 10);
        kazSchool.getAllTrainings();
    }
}


Java Example :
1. I have added some un necessary console print to get help in debugging.
2. For constructing scenario, I wrote code in main, you can define in separate function.

C# Example :
1. I have change some method names and make them as property
2. I have change some functions names as dot net works differently.

Uses :
- When a set of objects communicates in a well defined but complex ways.( The inter-dependencies are UN-structured or difficult to understand)
- When we need to re use an object but that object is referred to other related objects.
- When we need to implement a behavior which is distributed among several classes.(should be customizable without a lot of sub classing)

Thanks...:)

No comments:

Post a Comment