深入浅出设计模式——中介者模式(Mediator Pattern)

模式动机

在用户与用户直接聊天的设计方案中,用户对象之间存在很强的关联性,将导致系统出现如下问题:
 系统结构复杂:对象之间存在大量的相互关联和调用,若有一个对象发生变化,则需要跟踪和该对象关联的其他所有对象,并进行适当处理。
 对象可重用性差:由于一个对象和其他对象具有很强的关联,若没有其他对象的支持,一个对象很难被另一个系统或模块重用,这些对象表现出来更像一个不可分割的整体,职责较为混乱。
 系统扩展性低:增加一个新的对象需要在原有相关对象上增加引用,增加新的引用关系也需要调整原有对象,系统耦合度很高,对象操作很不灵活,扩展性差。
在面向对象的软件设计与开发过程中,根据“单一职责原则”,我们应该尽量将对象细化,使其只负责或呈现单一的职责。
对于一个模块,可能由很多对象构成,而且这些对象之间可能存在相互的引用,为了减少对象两两之间复杂的引用关系,使之成为一个松耦合的系统,我们需要使用中介者模式,这就是中介者模式的模式动机。

模式定义
中介者模式(Mediator Pattern)定义:用一个中介对象来封装一系列的对象交互,中介者使各对象不需要显式地相互引用,从而使其耦合松散,而且可以独立地改变它们之间的交互。中介者模式又称为调停者模式,它是一种对象行为型模式。
Mediator Pattern: Define an object that encapsulates how a set of objects interact. Mediator promotes loose coupling by keeping objects from referring to each other explicitly, and it lets you vary their interaction independently.
Frequency of use: medium low
UML图

模式结构
中介者模式包含如下角色:
Mediator: 抽象中介者
ConcreteMediator: 具体中介者
Colleague: 抽象同事类
ConcreteColleague: 具体同事类

模式分析
中介者模式可以使对象之间的关系数量急剧减少:
  

模式分析
中介者承担两方面的职责:
 中转作用(结构性):通过中介者提供的中转作用,各个同事对象就不再需要显式引用其他同事,当需要和其他同事进行通信时,通过中介者即可。该中转作用属于中介者在结构上的支持。
 协调作用(行为性):中介者可以更进一步的对同事之间的关系进行封装,同事可以一致地和中介者进行交互,而不需要指明中介者需要具体怎么做,中介者根据封装在自身内部的协调逻辑,对同事的请求进行进一步处理,将同事成员之间的关系行为进行分离和封装。该协调作用属于中介者在行为上的支持。
中介者模式就是迪米特法则的一个典型应用。

模式实例与解析
世界需要和平—中介者模式示例

体系结构

Mediator: 抽象中介者 UnitedNations.cs

namespace MediatorPattern
{
    //联合国机构 相当于Mediator类
    abstract class UnitedNations
    {
        public abstract void Declare(string message, Country colleague);
    }
}

ConcreteMediator: 具体中介者 UnitedNationsSecurityCouncil.cs

namespace MediatorPattern
{
    class UnitedNationsSecurityCouncil : UnitedNations
    {
        private USA colleaguel;
        private Iraq colleague2;
        //联合国安理会会了解所有的国家,所以拥有美国和伊拉克的对象属性
        public USA Colleague1
        {
            set { colleaguel = value; }
        }
        public Iraq Colleague2
        {
            set { colleague2 = value; }
        }

        public override void Declare(string message, Country colleague)
        {
            if (colleague == colleaguel)
            {
                colleague2.GetMessage(message);
            }
            else
            {
                colleaguel.GetMessage(message);
            }
        }
    }
}

Colleague: 抽象同事类 Country.cs

namespace MediatorPattern
{
    //国家 相当于Colleague类
    abstract class Country
    {
        protected UnitedNations mediator;
        public Country(UnitedNations mediator)
        {
            this.mediator = mediator;
        }
    }
}

ConcreteColleague: 具体同事类 USA.cs

using System;

namespace MediatorPattern
{
    //美国类 相当于ConcreteColleaguel类
    class USA : Country
    {
        public USA(UnitedNations mediator)
            : base(mediator)
        {
        }
        public void Declare(string message)
        {
            mediator.Declare(message, this);
        }
        //获得消息
        public void GetMessage(string message)
        {
            Console.WriteLine("美国获得对方信息:" + message);
        }
    }
}

Iraq.cs

using System;

namespace MediatorPattern
{
    //伊拉克类 相当于ConcreteColleague2类
    class Iraq : Country
    {
        public Iraq(UnitedNations mediator)
            : base(mediator)
        {
        }
        public void Declare(string message)
        {
            mediator.Declare(message, this);
        }
        //获得消息
        public void GetMessage(string message)
        {
            Console.WriteLine("伊拉克获得对方信息:" + message);
        }
    }
}

Client:客户类

using System;

namespace MediatorPattern
{
    class Program
    {
        static void Main(string[] args)
        {
            UnitedNationsSecurityCouncil UNSC = new UnitedNationsSecurityCouncil();
            USA c1 = new USA(UNSC);
            Iraq c2 = new Iraq(UNSC);

            UNSC.Colleague1 = c1;
            UNSC.Colleague2 = c2;
            c1.Declare("不准研制核武器,否则要发动战争!");
            c2.Declare("我们没有核武器,也不怕侵略");
            Console.Read();
        }
    }
}

模式优缺点
中介者模式的优点
 简化了对象之间的交互。
 将各同事解耦。
 减少子类生成。
 可以简化各同事类的设计和实现。
中介者模式的缺点
 在具体中介者类中包含了同事之间的交互细节,可能会导致具体中介者类非常复杂,使得系统难以维护。

模式适用环境
在以下情况下可以使用中介者模式:
 系统中对象之间存在复杂的引用关系,产生的相互依赖关系结构混乱且难以理解。
 一个对象由于引用了其他很多对象并且直接和这些对象通信,导致难以复用该对象。
 想通过一个中间类来封装多个类中的行为,而又不想生成太多的子类。可以通过引入中介者类来实现,在中介者中定义对象交互的公共行为,如果需要改变行为则可以增加新的中介者类。

【声明与感谢】
本文,站在许多巨人的肩膀上,借鉴和引用了许多他人拥有版权的作品或著述,在此,对前人们的贡献致谢。并同时公布引用的内容、原作者或来源(一些来源于互联网的内容本人无法追述本源,深表遗憾)。

【参考文献】
《设计模式—可复用面向对象软件的基础》作者: [美] Erich Gamma / Richard Helm / Ralph Johnson / John Vlissides 译者: 李英军 / 马晓星 / 蔡敏 / 刘建中 等 机械工业出版社
《重构—改善既有代码的设计》作者: Martin Fowler译者:候捷 中国电力出版社
《敏捷软件开发—原则、模式与实践》作者: Robert C. Martin 清华大学出版社
《程序员修炼之道—从小工到专家》作者: Andrew Hunt / David Thomas 电子工业出版社
《Head First 设计模式》作者: 弗里曼 译者: O'Reilly Taiwan公司 中国电力出版社
《设计模式之禅》 作者: 秦小波 机械工业出版社
MSDN WebCast 《C#面向对象设计模式纵横谈》 讲师:李建忠
刘伟. 设计模式. 北京:清华大学出版社, 2011.
刘伟. 设计模式实训教程. 北京:清华大学出版社, 2012.
《大话设计模式》 作者: 程杰 清华大学出版社
《C#图解教程》作者: 索利斯 译者: 苏林 / 朱晔 人民邮电出版社
《你必须知道的.NET》作者: 王涛
《项目中的.NET》作者: 李天平 电子工业出版社
《Microsoft .NET企业级应用架构设计》作者: (美)埃斯波西托等编著 译者: 陈黎夫
http://www.dofactory.com/Patterns/Patterns.aspx .NET Design Patterns
http://www.cnblogs.com/zhenyulu 博客作者:吕震宇
http://www.cnblogs.com/terrylee 博客作者:李会军
http://www.cnblogs.com/anlyren/ 博客作者:anlyren
http://www.cnblogs.com/idior 博客作者:idior
http://www.cnblogs.com/allenlooplee 博客作者:Allen lee
http://blog.csdn.net/ai92 博客作者:ai92
http://www.cnblogs.com/umlonline/ 博客作者:张传波
http://www.cnblogs.com/lovecherry/ 博客作者:LoveCherry

posted @ 2014-12-31 14:26  Bobby0322  阅读(1049)  评论(0编辑  收藏  举报