定义:用一个中介对象封闭一系列的对象交互,中介者使各对象不需要显示地相互作用,从而使其耦合松散,而且可以独立地改变它们之间的交互。
把原有的一对多的依赖变成了一对一的依赖,但随即带来的是中介者类的复杂和庞大。
中介者模式适用于多个对象之间紧密耦合的情况,紧密耦合的标准是:在类图中出现了蜘蛛网状结构,这种情况下一定考虑中介者模式,有利于把蜘蛛网梳理为星型结构,使原本复杂混乱的关系变得清晰简单。
一、普通进货、销售、库存的例子
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电脑
三、 中介者模式的定义
用一个中介对象封闭一系列的对象交互,中介者使各对象不需要显示地相互作用,从而使其耦合松散,而且可以独立地改变它们之间的交互。
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框架,但不是项目开发,项目是以交付为目的,产品是以稳定、高效、扩展有宗旨。