面向对象编程思想-中介者模式

Posted 快跑啊兔兔

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了面向对象编程思想-中介者模式相关的知识,希望对你有一定的参考价值。

一、引言

前两天休息日在网上打QQ斗地主,每盘结束后腾讯游戏平台会自动计算输赢的欢乐豆,嗯?挺好的,平时在面对面玩斗地主时,一盘游戏结束后,我们需要了解每个人的出牌状况,然后算出来输赢。现在有了游戏平台,玩家之间计算输赢这个操作交给了游戏平台,我们不再需要了解每个人的出牌状况。在软件设计中,我们将解决这种业务场景的模式称之为中介者模式

二、中介者模式

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

下面是中介者模式结构图:

为什么要使用中介者模式?

如果不使用中介者模式,各个同事对象将相互引用,如果每个对象都与多个对象交互时,将形成下图所示网状结构:

分析:上图中每个对象之间过度耦合,不利于类的复用也不利于扩展。假如对象一变化了将可能引起与它直接相依赖的所有对象的调整,所以同事对象之间直接依赖不是好的设计。

如果采用中介者模式,那么对象之间的关系将变成下图所示星型结构;

分析:使用中介者模式后,任何一个同事对象的变化,只会影响中介者和类本身,不会像之前设计中一个对象变化,将会引用所有与之关联的对象变化

场景:两个人本金都是100,在一起打牌,每盘结束后计算两个人的金额

下面是不使用中介者模式的demo:

     //抽象同事类  充当牌友类
    public abstract class Colleague
    {
        public int Number
        {
            get;
            set;
        }
        public abstract void Win(int number, Colleague colleague);
    }
    //牌友A类
    public class ConcreteColleagueA : Colleague
    {
        public override void Win(int number, Colleague colleague)
        {
            this.Number += number;
            colleague.Number -= number;
        }      
    }
    //牌友B类
    class ConcreteColleagueB : Colleague
    {
        public override void Win(int number, Colleague colleague)
        {
            this.Number += number;
            colleague.Number -= number;
        }
    }
     class Program
    {
        static void Main(string[] args)
        {
            //A和B两个人打牌
            Colleague colleagueA = new ConcreteColleagueA();
            Colleague colleagueB = new ConcreteColleagueB();
            colleagueA.Number = 100;
            colleagueB.Number = 100;
            //A赢了B就输钱
            colleagueA.Win(5, colleagueB);
            Console.WriteLine($"A的数量为{colleagueA.Number}");
            Console.WriteLine($"B的数量为{colleagueA.Number}");

            Console.Read();
        }
    }
View Code

分析:上述确实解决了场景中的问题,牌友A和牌友B都依赖于抽象,从而降低同事类之间的耦合度。这样的设计中,牌友A的变化会引起牌友B的变化,但是如果现在要新增一个牌友C、D、E呢?设计到多个对象的变化时,当前同事类需要了解其他所有涉及的同事类状况,这时就需要修改同事类了,而且,多个牌友计算输赢时任何一个人计算错误,都会导致整个业务场景中的计算错误。基于此思考,能不能把计算的钱的任务交给程序做呢?譬如QQ斗地主。。。即引入中介者对象来协调各个对象之间的关系

下面是引入中介者对象的代码demo

//抽象同事类
    public abstract class Colleague
    {
        public int Number
        {
            get;
            set;
        }
        public abstract void Win(int number, Mediator mediator);
    }
     //抽象中介者类
    public abstract class Mediator
    {
        public ConcreteColleagueA A;
        public ConcreteColleagueB B;
        public Mediator(ConcreteColleagueA a, ConcreteColleagueB b)
        {
            A = a;
            B = b;
        }
        public abstract void AWin(int number);
        public abstract void BWin(int number);
    }
    public class ConcreteColleagueA : Colleague
    {
        public override void Win(int number, Mediator mediator)
        {
            mediator.AWin(number);
        }
    }
     public class ConcreteColleagueB : Colleague
    {
        public override void Win(int number, Mediator mediator)
        {
            mediator.BWin(number);
        }
    }
    class ConcreteMediator : Mediator
    {
        public ConcreteMediator(ConcreteColleagueA a, ConcreteColleagueB b) : base(a,b)
        { }

        public override void AWin(int number)
        {
            A.Number += number;
            B.Number -= number;
        }
        public override void BWin(int number)
        {
            A.Number -= number;
            B.Number += number;
        }
     }   
    class Program
    {
        static void Main(string[] args)
        {
            ConcreteColleagueA concreteColleagueA = new ConcreteColleagueA();
            ConcreteColleagueB concreteColleagueB = new ConcreteColleagueB();
            ConcreteMediator concreteMediator = new ConcreteMediator(concreteColleagueA, concreteColleagueB);
            concreteColleagueA.Number = 100;
            concreteColleagueB.Number = 100;
            concreteMediator.AWin(5);
            Console.WriteLine($"A的数量为{concreteColleagueA.Number}");
            Console.WriteLine($"B的数量为{concreteColleagueB.Number}");
            Console.WriteLine();
            Console.Read();
        }
    }  
View Code

分析:运行结果和上面不使用中介者模式的代码运行结果一致,这样如果某个牌友类变化时,只会影响到该变化的牌友类和中介者类,从而解决上面代码中的问题。

但是此时如果要新增一个牌友类,我们就不得不修改抽象中介者类,还可以再完善一下吗?完全可以,我们可以结合观察者模式,在抽象中介者类中保存一个抽象牌友类的集合,添加保存删除牌友的方法管理集合,然后在具体的中介者类中,修改AWin()、BWin()循环遍历执行改变自己和其他牌友的钱数。此时仍然存在一个问题,新增牌友时,我们虽然不需要修改抽象中介者类,但是还是要在具体中介者类中添加CWin()方法,这时可以此采用状态模式来解决问题,具体会在下一个专题中介绍。

下面是大话设计模式中的例子辅助理解中介者模式:

    abstract class Colleague
    {
        protected Mediator mediator;
        public Colleague(Mediator mediator)
        {
            this.mediator = mediator;
        }
    }
    abstract class Mediator
    {
        public abstract void Send(string message, Colleague colleague);
    }
     class ConcreteColleagueA : Colleague
    {
        public ConcreteColleagueA(Mediator mediator) : base(mediator)
        {

        }
        public void Send(string message)
        {
            mediator.Send(message, this);
        }
        public void Notify(string message)
        {
            Console.WriteLine("同事A得到消息:"+message);
        }
    }
     class ConcreteColleagueB : Colleague
    {
        public ConcreteColleagueB(Mediator mediator) : base(mediator)
        {

        }
        public void Send(string message)
        {
            mediator.Send(message, this);
        }
        public void Notify(string message)
        {
            Console.WriteLine("同事B得到消息:" + message);
        }
    }
    class ConcreteMediator : Mediator
    {
        private ConcreteColleagueA concreteColleagueA;
        private ConcreteColleagueB concreteColleagueB;
        public ConcreteColleagueA ConcreteColleagueA
        {
            set { concreteColleagueA = value; }
        }
        public ConcreteColleagueB ConcreteColleagueB
        {
            set { concreteColleagueB = value; }
        }
        public override void Send(string message, Colleague colleague)
        {
            if(colleague==concreteColleagueA)
            {
                concreteColleagueB.Notify(message);
            }
            else if(colleague==concreteColleagueB)
            {
                concreteColleagueA.Notify(message);
            }
        }
    }
     class Program
    {
        static void Main(string[] args)
        {
            ConcreteMediator concreteMediator = new ConcreteMediator();
            ConcreteColleagueA concreteColleagueA = new ConcreteColleagueA(concreteMediator);
            ConcreteColleagueB concreteColleagueB = new ConcreteColleagueB(concreteMediator);
            concreteMediator.ConcreteColleagueA = concreteColleagueA;
            concreteMediator.ConcreteColleagueB = concreteColleagueB;
            concreteColleagueA.Send("你吃过饭了吗?");
            concreteColleagueB.Send("我吃过了");
            Console.Read();
        }
    }
View Code

优点:

1.将系统各个对象之间的关系进行封装,将各个同事类解耦,使系统松耦合

2.将对象间一对多关系转变为一对一关联,使对象间关系易于理解和维护

3.提高系统灵活性,使各个同事类独立而易于复用

缺点:

1.中介者承担的责任太重,一旦中介者出现问题,整个系统将会受到影响

2.新增加一个同事类时,不得不修改抽象中介者类和具体的中介者类

适用场景:

1.一组定义好的关系,要进行复杂的通信(如最开始对象间关系成网状结构)时,使用中介者模式可以使同事类间关系更清晰

2.想通过一个中间类来封装多个类中的行为

 

本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接。

参照:

1.大话设计模式

2.http://www.cnblogs.com/zhili/p/MediatorPattern.html

以上是关于面向对象编程思想-中介者模式的主要内容,如果未能解决你的问题,请参考以下文章

面向对象编程思想-简单工厂模式

面向对象编程思想-代理模式

面向对象编程思想-单例模式

VSCode自定义代码片段——JS中的面向对象编程

面向对象编程思想-组合模式

VSCode自定义代码片段9——JS中的面向对象编程