Java设计模式之中介者模式

中介者模式也叫作调停模式,是处理项目中网状结构的一种设计模式。中介者,顾名思义就是周旋在各方中间的协调者,它让系统的各个模块之间可以单独的运转。

定义

中介者模式是封装了一系列对象之间相互作用的方式,将对象之间的强耦合关系变成一种松散耦合关系。该模式将一种多对多的关系转变成一种以中介者为中心的一对多关系,从而使各个对象可以进行独立的自主变化。

场景

当系统中有多个对象相互作用时,修改一个对象会导致其他对象都发生变化。此时,可以引入中介者模式,将网状结构转换成星型结构,降低系统复杂性,提高扩展性。

角色

抽象中介者角色

中介者类的抽象,一般定义了其他模块对象到中介者对象的接口,多数为抽象类。

具体中介者

对抽象中介者的实现,它实现了抽象中介者的方法,定义了从其他模块对象接收消息以及发送消息的行为

其他模块的抽象

定义了中介者对象的接口,它只知道中介者的存在

其他模块的抽象具体实现

实现于其他模块的抽象,定义了自身的行为

说明

通过上面的描述,可能有些人发现了中介者和其他模块之间具备强耦合关系,事实上,的确如此,中介者模式借助于这种强耦合关系来降低其他模块之间的耦合程度。中介者担任一个消息传递的角色,从一个模块接收消息,然后通知其他模块进行自我改变。基于这种结构,中介者本身就不免会显得有些臃肿。

代码演示

中介者在现实生活中也很常见,比如房屋中介、汽车销售中介等等。我们就房屋中介这个场景来看下具体实现。这个场景下有三个角色,中介、买方、卖方。首先我们定义买卖方抽象。

/**
 * 抽象模块角色,持有一个中介者的引用
 */
public abstract class ICustomer {

  protected AbstractMediator mediator;

  public ICustomer(AbstractMediator mediator) {
    this.mediator = mediator;
  }

  public abstract String getName();
}

接下来实现卖方和买方

/**
 * 卖方
 */
public class Seller extends ICustomer {

  public Seller(AbstractMediator mediator) {
    super(mediator);
  }

  @Override public String getName() {
    return "卖方";
  }

  /**
   * 卖方行为
   */
  public void sell(double price) {
    System.out.println("卖家同意以" + price + "W的价格出售房屋");
  }

  public double getLowestPrice() {
    return 195.0D;
  }

  /**
   * 上架房源,通知中介者
   */
  public void upload() {
    System.out.println("卖家预以200.0W的价格出售房屋");
    mediator.coordinate(this);
  }
}
/**
 * 买家
 */
public class Purchaser extends ICustomer {

  private double offeredPrice = 190.0D;

  public Purchaser(AbstractMediator mediator) {
    super(mediator);
  }

  @Override public String getName() {
    return "买方";
  }

  public double getPrice() {
    return offeredPrice;
  }

  /**
   * 买家决定调价买入,让中介者告知卖方
   */
  public void buy() {
    offeredPrice = 195.0D;
    System.out.println(getName() + "调价到195.0W资金购买房屋");
    mediator.coordinate(this);
  }

  /**
   * 买家寻找房源的行为
   */
  public void search() {
    System.out.println(getName() + "准备190.0W资金购买房屋");
  }
}

然后看下中介者抽象以及实现

/**
 * 抽象中介者
 */
public abstract class AbstractMediator {

  /**
   * 接收消息的方法
   */
  public abstract void coordinate(ICustomer customer);
}
/**
 * 抽象者具体实现
 */
public class Mediator extends AbstractMediator {

  /**
   * 模块一实现
   */
  private Seller seller;
  /**
   * 模块二实现
   */
  private Purchaser purchaser;

  public void setSeller(Seller seller) {
    this.seller = seller;
  }

  public void setPurchaser(Purchaser purchaser) {
    this.purchaser = purchaser;
  }

  @Override public void coordinate(ICustomer customer) {
    // 如果是买方传递过来的消息,则通知买方
    if (customer == seller) {
      purchaser.search();
      purchaser.buy();
    } else if (customer == purchaser) {
      if (purchaser.getPrice() >= seller.getLowestPrice()) {
        seller.sell(purchaser.getPrice());
      } else {
        System.out.println("双方价格没有谈拢,终止交易");
      }
    }
  }
}

在一次买卖行为中,卖方会先上传房源到中介平台,中介平台查询适合的房屋通知买方,询价,最后通知卖方交易。在代码层面,首先要建立买卖双方和中介的星型结构

  public static void main(String[] args) {
    // 构建中介者模式星型结构
    Mediator mediator = new Mediator();
    Purchaser purchaser = new Purchaser(mediator);
    Seller seller = new Seller(mediator);
    mediator.setPurchaser(purchaser);
    mediator.setSeller(seller);
    // 准备卖房
    seller.upload();
  }

然后会触发一次交易流程

卖家预以200.0W的价格出售房屋
买方准备190.0W资金购买房屋
买方调价到195.0W资金购买房屋
卖家同意以195.0W的价格出售房屋

到此,交易结束,在这个交易流程中,买卖双方只知道中介者的存在,不知道彼此的存在,可以让买卖双方进行自主变化(调价),提高了系统的灵活性。需要注意的是,在中介者实现中,模块类型是实例类型,而非接口类型,违背了依赖倒置原则。当然了,这也是为了实现各个模块的自我变化的一种妥协。

关于源码

在安卓中,系统层的KeyguardViewMediator类就运用了中介者模式,它持有了几个管理类,也就是模块对象,各个模块通过KeyguardViewMediator来进行通信和协调工作

public class KeyguardViewMediator extends SystemUI {

    private AlarmManager mAlarmManager;
    private AudioManager mAudioManager;
    private StatusBarManager mStatusBarManager;
    ...
    
    private void adjustStatusBarLocked(boolean forceHideHomeRecentsButtons) {
        if (mStatusBarManager == null) {
            mStatusBarManager = (StatusBarManager)
                    mContext.getSystemService(Context.STATUS_BAR_SERVICE);
        }
        ...
        mStatusBarManager.disable(flags);
        ...
        }
    }
    
    
}

上图中适配锁屏时状态栏状态的方法就是由StatusBarManager具体实施的。

总结

中介者模式是针对复杂的网状结构进行解耦的设计,当一个系统内有很多对象彼此之间有交互,构成比较繁杂的网状结构,这个时候就应该考虑使用中介者模式来解耦合。当然了,如果只是几个对象之间的交互,并且没有构成复杂的网状体系,则没有要使用中介者模式了。总之,在使用一种设计模式时,需要权衡下利弊。

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 199,711评论 5 468
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 83,932评论 2 376
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 146,770评论 0 330
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 53,799评论 1 271
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 62,697评论 5 359
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,069评论 1 276
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,535评论 3 390
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,200评论 0 254
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,353评论 1 294
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,290评论 2 317
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,331评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,020评论 3 315
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,610评论 3 303
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,694评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,927评论 1 255
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,330评论 2 346
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 41,904评论 2 341

推荐阅读更多精彩内容