定义:用一个中介对象封闭一系列的对象交互,中介者使各对象不需要显示地相互作用,从而使其耦合松散,而且可以独立地改变它们之间的交互。

把原有的一对多的依赖变成了一对一的依赖,但随即带来的是中介者类的复杂和庞大。

中介者模式适用于多个对象之间紧密耦合的情况,紧密耦合的标准是:在类图中出现了蜘蛛网状结构,这种情况下一定考虑中介者模式,有利于把蜘蛛网梳理为星型结构,使原本复杂混乱的关系变得清晰简单。

一、普通进货、销售、库存的例子

1. 采购管理

public class Purchase {
	//采购IBM电脑
	public void buyIBMcomputer(int number){
		//访问库存
		Stock stock = new Stock();
		//访问销售
		Sale sale = new Sale();
		//电脑的销售情况
		int saleStatus = sale.getSaleStatus();
		if(saleStatus > 80){	//销售情况好
			System.out.println("采购IBM电脑:"+number+"台");
			stock.increase(number);
		}else{	//销售情况不好
			int buyNumber = number/2;
			System.out.println("采购IBM电脑:"+buyNumber+"台");
			stock.increase(buyNumber);
		}
	}
	//不再采购IBM电脑
	public void refuseBuyIBM(){
		System.out.println("不再采购IBM电脑");
	}
}


2. 库存管理

public class Stock {
	//刚开始有100台电脑(该变量属于类,线程共享,所以所有线程都可以访问或修改该变量)
	private static int COMPUTER_NUMBER = 100;
	//库存增加
	public void increase(int number){
		COMPUTER_NUMBER = COMPUTER_NUMBER + number;
		System.out.println("库存数量为:"+COMPUTER_NUMBER);
	}
	//库存降低
	public void decrease(int number){
		COMPUTER_NUMBER = COMPUTER_NUMBER - number;
		System.out.println("库存数量为:"+COMPUTER_NUMBER);
	}
	//获得库存数量
	public int getStockNumber(){
		return COMPUTER_NUMBER;
	}
	//存货压力大了,就要通知采购人员不要采购,销售人员要尽快销售
	public void clearStock(){
		Purchase purchase = new Purchase();
		Sale sale = new Sale();
		System.out.println("清理存货数量为:"+COMPUTER_NUMBER);
		//要求折价销售
		sale.offSale();
		//要求采购人员不要采购了
		purchase.refuseBuyIBM();
	}
}


3. 销售管理

public class Sale {
	//销售IBM电脑
	public void sellIBMComputer(int number){
		//访问库存
		Stock stock = new Stock();
		//访问采购
		Purchase purchase = new Purchase();
		if(stock.getStockNumber() < number){	//库存数量不够销售
			purchase.buyIBMcomputer(number);
		}
		System.out.println("销售IBM电脑"+number+"台");
		stock.decrease(number);
	}
	//反馈销售情况,0~100之间变化,0代表根本就没人买,1000代表非常畅销,出一个卖一个
	public int getSaleStatus(){
		Random random = new Random(System.currentTimeMillis());
		int saleStatus = random.nextInt(100);
		System.out.println("IBM电脑的销售情况为:"+saleStatus);
		return saleStatus;
	}
	//折价处理
	public void offSale(){
		//库房有多少卖多少
		Stock stock = new Stock();
		System.out.println("折价销售IBm电脑:"+stock.getStockNumber()+"台");
	}
}


4. 场景类

public class Client {
	public static void main(String[] args) {
		//采购人员采购电脑
		System.out.println("-------采购人员 采购电脑---------");
		Purchase purchase = new Purchase();
		purchase.buyIBMcomputer(100);
		//销售人员销售电脑
		System.out.println("-------销售人员 销售电脑---------");
		Sale sale = new Sale();
		sale.sellIBMComputer(1);
		//库房管理人员管理库存
		System.out.println("-------库房管理人员清库处理------");
		Stock stock = new Stock();
		stock.clearStock();
	}
}


二、引入中介者模式

1. 抽象中介者

public abstract class AbstractMediator {
	protected Purchase purchase;
	protected Sale sale;
	protected Stock stock;
	//构造函数
	public AbstractMediator() {
		purchase = new Purchase(this);
		sale = new Sale(this);
		stock = new Stock(this);
	}
	//中介者最重要的方法叫做事件方法,处理多个对象之间的关系
	public abstract void execute(String str,Object...object);
}


2. 具体中介者

中介者Mediator定义了多个private方法,其目的是处理各个对象之间的依赖关系,就是说把原有一个对象要依赖多个对象的情况移到中介者的private方法中实现。在实际项目中,一般的做法是中介者按照职责进行划分,每个中介者处理一个或多个类似的关联请求。

public class Mediator extends AbstractMediator{
	public void execute(String str, Object... objects) {
		if(str.equals("purchase.buy")){			//采购电脑
			this.buyComputer((Integer)objects[0]);
		}else if(str.equals("sale.sell")){		//销售电脑
			this.sellComputer((Integer)objects[0]);
		}else if(str.equals("sale.offsell")){	//折价销售
			this.offSell();
		}else if(str.equals("stock.clear")){	//清仓处理
			this.clearStock();
		}
	}
	//采购电脑
	private void buyComputer(int number){
		int saleStatus = super.sale.getSaleStatus();
		if(saleStatus>80){	//销售情况良好
			System.out.println("采购IBM电脑:"+number+"台");
			super.stock.increase(number);
		}else{	//销售情况不好
			int buyNumber = number/2;
			System.out.println("采购IBM电脑:"+buyNumber+"台");
			super.stock.increase(buyNumber);
		}
	}
	//销售电脑
	private void sellComputer(int number){
		if(super.stock.getStockNumber()<number){
			super.purchase.buyIBMcomputer(number);
		}
		super.stock.decrease(number);
	}
	//折价销售电脑
	private void offSell(){
		System.out.println("折价销售IBM电脑:"+stock.getStockNumber()+"台");
	}
	//清仓处理
	private void clearStock(){
		//要求清仓销售
		super.sale.offSale();
		//要求采购人员不要采购
		super.purchase.refuseBuyIBM();
	}
}


3. 抽象同事类

public abstract class AbstractColleague {
	protected AbstractMediator mediator;
	public AbstractColleague(AbstractMediator mediator) {
		this.mediator = mediator;
	}
}


4. 修改后的采购管理

public class Purchase extends AbstractColleague{
	public Purchase(AbstractMediator mediator) {
		super(mediator);
	}
	//采购IBM电脑
	public void buyIBMcomputer(int number){
		super.mediator.execute("purchase.buy", number);
	}
	//不再采购IBM电脑
	public void refuseBuyIBM(){
		System.out.println("不再采购IBM电脑");
	}
}


5. 修改后的库存管理

public class Stock extends AbstractColleague{
	public Stock(AbstractMediator mediator) {
		super(mediator);
	}
	//刚开始有100台电脑(该变量属于类,线程共享,所以所有线程都可以访问或修改该变量)
	private static int COMPUTER_NUMBER = 100;
	//库存增加
	public void increase(int number){
		COMPUTER_NUMBER = COMPUTER_NUMBER + number;
		System.out.println("库存数量为:"+COMPUTER_NUMBER);
	}
	//库存降低
	public void decrease(int number){
		COMPUTER_NUMBER = COMPUTER_NUMBER - number;
		System.out.println("库存数量为:"+COMPUTER_NUMBER);
	}
	//获得库存数量
	public int getStockNumber(){
		return COMPUTER_NUMBER;
	}
	//存货压力大了,就要通知采购人员不要采购,销售人员要尽快销售
	public void clearStock(){
		System.out.println("清理存货数量为:"+COMPUTER_NUMBER);
		super.mediator.execute("stock.clear");
	}
}


6. 修改后的销售管理

public class Sale extends AbstractColleague{
	public Sale(AbstractMediator mediator) {
		super(mediator);
	}
	//销售IBM电脑
	public void sellIBMComputer(int number){
		super.mediator.execute("sale.sell", number);
		System.out.println("销售IBM电脑"+number+"台");
	}
	//反馈销售情况,0~100之间变化,0代表根本就没人买,1000代表非常畅销,出一个卖一个
	public int getSaleStatus(){
		Random random = new Random(System.currentTimeMillis());
		int saleStatus = random.nextInt(100);
		System.out.println("IBM电脑的销售情况为:"+saleStatus);
		return saleStatus;
	}
	//折价处理
	public void offSale(){
		//库房有多少卖多少
		this.mediator.execute("sale.offsell");
	}
}


7. 修改后的场景类

public class Client {
	public static void main(String[] args) {
//		//采购人员采购电脑
//		System.out.println("-------采购人员 采购电脑---------");
//		Purchase purchase = new Purchase();
//		purchase.buyIBMcomputer(100);
//		//销售人员销售电脑
//		System.out.println("-------销售人员 销售电脑---------");
//		Sale sale = new Sale();
//		sale.sellIBMComputer(1);
//		//库房管理人员管理库存
//		System.out.println("-------库房管理人员清库处理------");
//		Stock stock = new Stock();
//		stock.clearStock();
		
		AbstractMediator mediator = new Mediator();
		//采购人员采购电脑
		System.out.println("---------采购人员 采购电脑----------");
		Purchase purchase = new Purchase(mediator);
		purchase.buyIBMcomputer(100);
		//销售人员销售电脑
		System.out.println("---------销售人员销售电脑----------");
		Sale sale = new Sale(mediator);
		sale.sellIBMComputer(1);
		//库房管理人员管理库存
		System.out.println("---------库存管理人员清库处理-------");
		Stock stock = new Stock(mediator);
		stock.clearStock();
	}
}

==> 

---------采购人员 采购电脑----------


IBM电脑的销售情况为:40


采购IBM电脑:50台


库存数量为:150


---------销售人员销售电脑----------


库存数量为:149


销售IBM电脑1台


---------库存管理人员清库处理-------


清理存货数量为:149


折价销售IBM电脑:149台


不再采购IBM电脑

三、 中介者模式的定义

用一个中介对象封闭一系列的对象交互,中介者使各对象不需要显示地相互作用,从而使其耦合松散,而且可以独立地改变它们之间的交互。                                                         

中介变量和调节变量在基础回归中需要放在控制变量吗_System

Mediator抽象中介者角色:抽象中介者角色定义统一的接口,用于各同事角色之间的通信。

Concrete Mediator具体中介者角色:通过协调各同事角色实现协作行为,因此它必须依赖于各个同事角色。

Colleague同事角色:每一个同事角色都知道中介者角色,而且与其他的同事角色通信时,一定要通过中介者角色协作。每个同事类的行为分为两种:一种是同事本身的行为,比如改变对象本身的状态,处理自己的行为等,这种行为叫做自发行为(Self-Mehtod),与其他的同事类或中介 者没有任何的依赖;第二种是必须依赖中介者才能完成的行为,叫做依赖方法(Dep-Method)

1. 通用抽象中介者

public abstract class Mediator {
	//定义同事类
	protected ConcreteColleague1 c1;
	protected ConcreteColleague2 c2;
	//通过getter/setter方法把同事类注入进来
	public ConcreteColleague1 getC1() {
		return c1;
	}
	public void setC1(ConcreteColleague1 c1) {
		this.c1 = c1;
	}
	public ConcreteColleague2 getC2() {
		return c2;
	}
	public void setC2(ConcreteColleague2 c2) {
		this.c2 = c2;
	}
	//中介者模式的业务逻辑
	public abstract void doSomething1();
	public abstract void doSomething2();
}


在Mediator抽象类中只定义了同事类的注入,用的实现类注入而不是抽象类注入,原因是同事类虽然有抽象,但是没有每个同事类必须要完成的业务方法,当然,如果同事类都有相同的方法,比如execute/handler等,当然注入抽象类,做到依赖倒置。
2. 通用中介者

public class ConcreteMediator extends Mediator{
	public void doSomething1() {
		//调用同事类的方法,只要是public方法都可以调用
		super.c1.selfMethod1();
		super.c2.selfMethod2();
	}
	public void doSomething2() {
		super.c1.selfMethod1();
		super.c2.selfMethod2();
	}
}



中介者所有具有的方法doSomething1和doSomething2都是比较复杂的业务逻辑,为同事类服务,其实现是依赖各个同事类来完成的。

3. 抽象同事类

public abstract class Colleague {
	protected Mediator mediator;
	public Colleague(Mediator mediator) {
		this.mediator = mediator;
	}
}

这个基类是为了建立这个中介而服务的。


4. 具体同事类

public class ConcreteColleague1 extends Colleague{
	//通过构造函数传递中介者
	public ConcreteColleague1(Mediator mediator) {
		super(mediator);
	}
	//自有方法self-method
	public void selfMethod1(){
		
	}
	//依赖方法dep-method
	public void depMethod1(){
		//处理自己的业务逻辑
		//自己不能处理的业务逻辑、委托给中介者处理
		super.mediator.doSomething1();
	}
}

&


public class ConcreteColleague2 extends Colleague{
	//通过构造函数传递中介者
	public ConcreteColleague2(Mediator mediator) {
		super(mediator);
	}
	//自有方法 self-method
	public void selfMethod2(){
		//处理自己的业务逻辑
	}
	//依赖方法 dep-method
	public void depMethod2(){
		//处理自己的业务逻辑
		//自己不能处理的业务逻辑、委托给中介者处理
		super.mediator.doSomething2();
	}
}


为什么同事类要使用构造函数注入中介者,而中介者使用getter/setter方式注入同事类呢?这是因为同事类必须有中介者,而中介者却可以只有部分同事类。


四、中介者模式的应用

1. 优点

中介者模式的优点减少类间的依赖,把原有的一对多的依赖变成了一对一的依赖,同事类只就带中介者,减少了依赖,当然也降低了类间的耦合。

2. 缺点

缺点是中介者类会膨胀得很大,同事类越多,中介者的逻辑就越复杂。

3. 使用场景

中介者并非是有多个类的依赖就要用中介类模式,如果强行加入,会让中介者的逻辑复杂化。

中介者模式适用于多个对象之间紧密耦合的情况,紧密耦合的标准是:在类图中出现了蜘蛛网状结构,这种情况下一定考虑中介者模式,有利于把蜘蛛网梳理为星型结构,使原本复杂混乱的关系变得清晰简单。

五、中介者模式的实际应用

1. 机场调用中心 "调用中心"就是具体的中介者,用来调度每一架要降落和起飞的飞机,比如,某架飞机(同事类)买到机场上空了,就询问调试中心(中介者)“我是否可以降落”以及“降落到哪个跑道”,调试中心(中介者)查看其它飞机(同事类)情况,然后通知飞机降落。

2. MVC框架 C就是一个中介才,作用是把M业务逻辑和V视图隔离开,协调M和V协同工作,把M运行的结果和V代表的视图融合成一个前端可以展示的页面,减少M和V的依赖关系。

3. 可在如下的情况下尝试使用中介者模式

1)N个对象间产生了相互的依赖关系(N>2)

2)多个对象有依赖关系,但是依赖的行为尚不确定或者有发生改变的可能,在这种情况下一般建议采用中介者模式,降低变更引起的风险扩散。

3)产品开发,如果MVC框架,但不是项目开发,项目是以交付为目的,产品是以稳定、高效、扩展有宗旨。