目录

一、中介者模式是什么

二、中介者模式的适用场景

三、中介者模式结构

四、中介者模式实现方式

五、中介者模式的实现

六、中介者模式的优缺点

七、中介者模式和其他模式的区别

八、总结



f055fc2866b14165a50067b273247d32.png

一、中介者模式是什么

  • 定义

    是用来降低多个对象和类之间的通信复杂性。通过一个中介类处理不同类之间的通信,并支持松耦合,使代码易于维护。

  • 特性

    中介者模式又叫调停模式,是迪米特法则的典型应用,属于行为型模式。

  • 主要作用

    • 当对象与对象之间存在大量的关联关系时,系统的结构变得很复杂,牵一发而动全身,属于一种【网状结构】。中介者模式通过一个中介对象来封装一系列对象之间的交互,使原有对象之间的耦合松散,且可以独立地改变它们之间的交互,属于一种【星形结构】。

    • 对象之间的关联关系由【网状结构】变为【星形结构】可以将大大降低它们之间的耦合性。

  • 1e660f2b174442a48d5574bb10c22d58.png

二、中介者模式的适用场景

  • 适用场景

    • 当对象之间存在复杂的网状结构关系而导致依赖关系混乱且难以复用时,可使用中介者模式。

    • 当想创建一个运行于多个类之间的对象,又不想生成新的子类时,可使用中介者模式。

    • 当组件因过于依赖其他组件而无法在不同应用中复用时, 可使用中介者模式。

  • 【生活案例】

    • MVC 框架中,控制器(C)就是模型(M)和视图(V)的中介者

    • 微信聊天的中服务器是用户之间的中介者。

    • 房产中介是房屋买卖双方的中介者。

    • 塔台是飞机之间的中介者。

bdd63dd7b5cf40fa852a91a63c1e0087.png

三、中介者模式结构

  • 抽象中介者(Mediator)角色:定义统一的接口,用于各组件角色之间的通信,提供了组件对象注册与转发组件对象信息的抽象方法。

  • 具体中介者(Concrete Mediator)角色:实现中介者接口,通过一个List 来管理组件对象,协调各个组件角色之间的交互关系,有时会对组件角色生命周期进行管理。

  • 抽象组件类(Component)角色:定义组件类的接口,持有一个中介者对象的引用,提供组件对象交互的抽象方法,实现组件类的公共行为。

    网上很多人把抽象组件类(Component)角色称之为抽象同事类(Colleague)角色,是一个意思,只是我个人喜欢叫组件,所以本文都称为组件类。

  • 具体组件类(Concrete Component)角色:继承抽象组件类,实现自己的业务,它并不知道其他组件类的具体行为,在需要时通过与中介者通信,中介者会负责与其它的组件交互。

  • 客户端(Client)角色:创建具体中介者对象,并将具体组件类并与该中介者进行绑定。

82be314372dc4c9e99a773cc36edda36.png

四、中介者模式实现方式

  • 声明中介者接口并描述中介者和各种组件之间所需的交流接口。通常仅包括一个通知方法

  • 声明具体中介者类实现中介者接口,**持有一个List 来管理组件对象。**也可以让中介者负责组件对象的创建和销毁。

  • 声明抽象组件抽象类,持有一个中介者对象的引用,通过构造函数建立与中介者的连接。声明公共方法。

  • 声明具体组件类,继承抽象组件类,实现调用中介者的通知方法。

  • 客户端创建具体中介者对象,并将具体组件类并与该中介者进行绑定。

五、中介者模式的实现

【案例】:多架飞机需要跑道降落,塔台指挥。

【案例说明】:每一架飞机都是一个组件,拥有一些相同的行为,塔台作为中介者指挥飞机降落。

  • 抽象中介者(Mediator)角色

    /**
     * 抽象中介者(Mediator)角色 : 塔台
     */
    publicinterface TowerMediator {
        /**
         * 通知方法 : 通知飞机降落
         * @param track
         */
        public abstract void notify(String type,String track);
    
        /**
         * 在中介者中添加组件类
         * @param colleague
         */
        public abstract void register(AirplaneComponent colleague);
        /**
         * 在中介者中移除组件类
         * @param colleague
         */
        public abstract void remove(AirplaneComponent colleague);
    }
    	
    
  • 具体中介者(Concrete Mediator)角色

    /**
     * 具体中介者(Concrete Mediator)角色 : 塔台实现类
     */
     publicclass AirlinerConcreteMediator implements TowerMediator{
        /**
         * 持有一个List 来管理组件对象。
         */
        private List<AirplaneComponent> colleagues;
        public AirlinerConcreteMediator() {
            this.colleagues = new ArrayList<AirplaneComponent>();
        }
    
        @Override
        public void notify(String type,String track) {
            for (AirplaneComponent airplaneComponent : colleagues) {
                if(!type.equalsIgnoreCase(airplaneComponent.airplaneType)){
                    continue;
                }
                airplaneComponent.landing(track);
            }
        }
    
        @Override
        public void register(AirplaneComponent colleague) {
            colleagues.add(colleague);
        }
    
        @Override
        public void remove(AirplaneComponent colleague) {
            colleagues.remove(colleague);
        }
    }
    
  • 抽象组件类(Component)角色

    /**
     * 抽象组件类(Component)角色 : 飞机
     */
    publicabstractclass AirplaneComponent {
        /**
         * 用于区分飞机的类型
         */
        public String airplaneType;
        /**
         * 持有一个中介者对象的引用
         */
        private TowerMediator towerMediator;
        public AirplaneComponent(String airplaneType,TowerMediator towerMediator) {
            this.airplaneType = airplaneType;
            this.towerMediator = towerMediator;
        }
    
        public abstract void landing(String track);
    }
    
  • 具体组件类(Concrete Component)角色

    /**
     * 具体组件类(Concrete Component)角色 : 客机
     */
    publicclass AirlinerConcreteComponent extends AirplaneComponent{
        /**
         * 通过构造函数建立与中介者的连接
         * @param towerMediator
         */
        public AirlinerConcreteComponent(String airplaneType,TowerMediator towerMediator) {
            super(airplaneType,towerMediator);
        }
    
        @Override
        public void landing(String track) {
            System.out.println("接到塔台通知,客机在" + track + "跑道降落!");
        }
    }
    
    
    
    /**
     * 具体组件类(Concrete Component)角色 : 战斗机
     */
    publicclass FighterConcreteComponent extends AirplaneComponent{
    
        /**
         * 通过构造函数建立与中介者的连接
         * @param towerMediator
         */
        public FighterConcreteComponent(String airplaneType,TowerMediator towerMediator) {
            super(airplaneType,towerMediator);
        }
    
        @Override
        public void landing(String track) {
            System.out.println("接到塔台通知,战斗机在" + track + "跑道降落!");
        }
    }
    
    
    
  • 客户端代码实现

    public static void main(String[] args) {
            /**
             * 创建具体中介者对象
             */
            TowerMediator towerMediator = new AirlinerConcreteMediator();
            /**
             * 将具体组件类并与该中介者进行绑定。
             */
            towerMediator.register(new AirlinerConcreteComponent("客机",towerMediator));
            towerMediator.register(new FighterConcreteComponent("战斗机",towerMediator));
            towerMediator.notify("客机","1");
            towerMediator.notify("战斗机","2");
        }
    
  • 案例输出结果

ac4d6fa7b3224a2180534e42b9ec04d7.png

六、中介者模式的优缺点

  • 符合单一职责原则,多个组件间的交流抽取到中介者中, 使其更易于理解和维护。

  • 符合迪米特法则,组件类之间各司其职。

  • 符合开闭原则,无需修改实际组件类就能增加新的中介者。

  • 将对象间的一对多关联转变为一对一的关联,提高系统的灵活性,降低了对象之间的耦合性,使得系统易于维护和扩展。

七、中介者模式和其他模式的区别

  • 【外观模式】和【中介者模式】的职责类似:它们都尝试在大量紧密耦合的类中组织起合作。

    • 外观模式为子系统中的所有对象定义了一个简单接口, 但是它不提供任何新功能。子系统本身不会意识到外观的存在。子系统中的对象可以直接进行交流。

    • 中介者模式将系统中组件的沟通行为中心化。各组件只知道中介者对象, 无法直接相互交流。

  • 【中介者模式】和【观察者模式】非常类似

    很多时候我们可以使用中介者模式来实现观察者模式, 中介者对象担当发布者的角色, 其他组件则作为订阅者, 可以订阅中介者的事件或取消订阅。

    • 中介者模式的目标是通过同一个中介者对象消除一系列系统组件之间的相互依赖。

    • 观察者模式的目标是在对象之间建立动态的单向连接, 使得部分对象可作为其他对象的附属发挥作用。

    • 中介者模式与业务相关,订阅/发布模式与业务无关。

八、总结

中介者是迪米特法则的一个典型应用,通过引入中介者对象,可以将系统的【网状结构】变成以中介者为中心的【星形结构】,中介者承担了中转作用和协调作用,简化了对象之间的交互,还可以进一步的控制组件类之间的交互。

 

Logo

开放原子开发者工作坊旨在鼓励更多人参与开源活动,与志同道合的开发者们相互交流开发经验、分享开发心得、获取前沿技术趋势。工作坊有多种形式的开发者活动,如meetup、训练营等,主打技术交流,干货满满,真诚地邀请各位开发者共同参与!

更多推荐