Mediator

Introduction

Object oriented programming allows us to define a lot of classes which are regarded as an encapsulated object. A perfect object knows only what it can do, what it needs, but never knows who uses it. And what’s more, when it cannot do something, the object would use other objects to accomplish the task when it doesn’t know the details of the other objects. That is, the relationship between the objects.

Usually our system would be very large and complex, and we defined lots of classes, there would be many connections between them, in the worst case, every objects end up knowing about every other. As a bad effect, making the system difficult to maintenance and/or refactoring.

Mediator pattern is designed to encapsulte the communiations between objects as an mediator object. Objects no longer communicate directly with each other, but instead communicate through the mediator, which reduces the dependencies between communicating objects, thereby lowering the coupling.

Definition

Define an object that encapsulates how a sets of objects interact. Mediator promotes loose coupling by keeping objects from referring each other explicitly, and it lets you vary their interaction independently.

UML class diagram

Mediator Pattern

Participants

  • Mediator
    • defines an interface for communication with Colleague objects.
  • ConcreteMediator
    • implements coorperative behavior by coordinating Colleague objects.
    • knows and maintains its colleagures.
  • Colleague classes
    • each Colleague class knows its Mediator Objects.
    • each Colleague communicate with its mediator whenever it would have otherwise communicated with another colleague.

Example

// Colleague
public interface Sender {
	
	void send();
	
	void execute();
	
	void cancel();
}


// Mediator
public interface Mediator {

	void sendByMail();
	
	void sendBySms();
	
	void sendByWechat();
	
	void registerMailSender(MailSender sender);
	
	void registerSmsSender(SmsSender sender);
	
	void registerWechatSender(WechatSender sender);
	
	void registerLogger(Logger logger);
}

// ConcreteMediator
public class MessageMediator implements Mediator {
	
	MailSender mailSender;
	SmsSender smsSender;
	WechatSender wechatSender;
	Logger logger;

	@Override
	public void sendByMail() {
		mailSender.execute();
		smsSender.cancel();
		wechatSender.cancel();
		logger.writeLog("sending by mail...\n");
	}

	@Override
	public void sendBySms() {
		smsSender.execute();
		mailSender.cancel();
		wechatSender.cancel();
		logger.writeLog("sending by sms...\n");
	}

	@Override
	public void sendByWechat() {
		wechatSender.execute();
		mailSender.cancel();
		smsSender.cancel();
		logger.writeLog("sending by wechat...\n");
	}

	@Override
	public void registerMailSender(MailSender sender) {
		mailSender = sender;
	}

	@Override
	public void registerSmsSender(SmsSender sender) {
		smsSender = sender;
	}

	@Override
	public void registerWechatSender(WechatSender sender) {
		wechatSender = sender;
	}

	@Override
	public void registerLogger(Logger logger) {
		this.logger = logger;
	}

}

// ConcreteColleague
public class MailSender implements Sender {
	
	private Mediator mediator;
	
	public MailSender(Mediator mediator) {
		this.mediator = mediator;
		this.mediator.registerMailSender(this);
	}

	@Override
	public void execute() {
		System.out.println("[MAIL]: sending message...");
	}

	@Override
	public void cancel() {
		System.out.println("[MAIL]: action has been canceled.");
	}

	@Override
	public void send() {
		mediator.sendByMail();
	}

}

public class SmsSender implements Sender {
	
	private Mediator mediator;
	
	public SmsSender(Mediator mediator){
		this.mediator = mediator;
		this.mediator.registerSmsSender(this);
	}

	@Override
	public void execute() {
		System.out.println("[SMS]: sending message...");
	}

	@Override
	public void cancel() {
		System.out.println("[SMS]: action has been canceled.");
	}

	@Override
	public void send() {
		mediator.sendBySms();
	}

}

public class WechatSender implements Sender {
	
	private Mediator mediator;
	
	public WechatSender(Mediator mediator) {
		this.mediator = mediator;
		this.mediator.registerWechatSender(this);
	}

	@Override
	public void execute() {
		System.out.println("[WECHAT]: sending message...");
	}

	@Override
	public void cancel() {
		System.out.println("[WECHAT]: action has been canceled.");
	}

	@Override
	public void send() {
		mediator.sendByWechat();
	}

}

// Client
public class Client {
	
	Mediator mediator = new MessageMediator();
	
	private MailSender mailSender;
	private SmsSender smsSender;
	private WechatSender wechatSender;
	private Logger logger;
	
	Client(){
		mailSender = new MailSender(mediator);
		smsSender = new SmsSender(mediator);
		wechatSender = new WechatSender(mediator);
		logger = new Logger(mediator);
	}
	
	void sendMessage(String type) {
		if(type.equalsIgnoreCase("mail")) {
			mailSender.send();
		} else if(type.equalsIgnoreCase("sms")) {
			smsSender.send();
		} else if(type.equalsIgnoreCase("wechat")){
			wechatSender.send();
		} else {
			logger.writeLog("ERROR: unsupported sender.");
		}
	}

	public static void main(String[] args) {
		Client client = new Client();
		client.sendMessage("mail");
		client.sendMessage("sms");
		client.sendMessage("wechat");
	}

}

Output

[MAIL]: sending message...
[SMS]: action has been canceled.
[WECHAT]: action has been canceled.
sending by mail...

[SMS]: sending message...
[MAIL]: action has been canceled.
[WECHAT]: action has been canceled.
sending by sms...

[WECHAT]: sending message...
[MAIL]: action has been canceled.
[SMS]: action has been canceled.
sending by wechat...

Usage

  • when a set of objects communicate in well-defined but complex ways. The resulting interdependencies are unstructured and difficult to understand.
  • when reusing an objects is difficult because it refers to and communicates with many other objects.
  • when a behavior that’s is distributed between several classes should be customizable without a lot of subclassing.

See Also

blog comments powered by Disqus