设计模式系列之Mediator模式

设计模式系列之Mediator模式(中介者模式)

意图

 

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

 

场景

 

我们知道,一个网络游戏往往有很多大区。每一个大区可以是一组服务器,也可以是多组服务器,在这里假设一个大区是一组服务器。为了效率,一般每个大区都会有一个数据库,玩家的创建角色、充值、消费行为只是在这一个大区中有效。现在公司有了新的需求,那就是玩家的一些信息能在多个大区中共享。比如,在注册的时候就把玩家的账户信息写入多个信息共享的大区,玩家在某个大区中充值需要“通知”其它大区修改账户余额,玩家在某个大区中消费也需要“通知”其它大区修改账户余额。

如果我们现在有ABC三个大区,下面的方法可以实现需求:

l         网站的注册方法调用A、B和C大区的注册方法

l         A大区的充值方法调用B和C的充值方法

l         B大区的充值方法调用A和C的充值方法

l         C大区的充值方法调用A和B的充值方法

l         A大区的消费方法调用B和C的充值方法

l         B大区的消费方法调用A和C的充值方法

l         C大区的消费方法调用A和B的充值方法

我想,没有人会这么做吧。你肯定会想到在一个统一的地方去维护所有大区的信息,任何一个大区的行为不直接和其它大区的行为关联,它们所有的行为都提交到一个统一的地方(假设它是AccountSystem)去处理。这么做有几个好处:

l         各大区不需要关心还有哪些其它的大区,它只直接和AccountSystem对话。

l         只需要调整AccountSystem就能调整各大区之间的交互行为,比如我们仅仅希望A和B大区共享信息、C和D大区共享信息,那么对于这种交互策略的改变也需要修改AccountSystem。

l         有利于大区的扩充,有了新的大区后,我们不用在大区中考虑它的交互行为,统一交给AccountSystem去安排。

现在,再来看看引入AccountSystem后的通讯:

l         网站调用AccountSystem的注册方法(1)

l         AccountSystem调用A、B和C大区的注册方法(2)

l         A、B和C大区的充值方法调用AccountSystem的充值方法(3)

l         A、B和C大区的消费方法调用AccountSystem的充值方法(4)

l         AccountSystem的充值方法调用A、B和C大区的专有充值方法(只针对本大区的充值)(5)

l         AccountSystem的充值方法调用A、B和C大区的专有消费方法(只针对本大区的消费)(6)

至此,你已经实现了中介者模式。你可能会觉得,(1)和(2)非常类似门面模式,没错,它确实就是门面模式,而有了(3)~(6)的行为,AccountSystem也就是一个中介者的角色了。

 

实例讲解:

 

using System;

using System.Collections.Generic;

using System.Text;

 

namespace MediatorExample

{

l         AccountSystem是一个中介者角色,它负责各个同事类之间的交互。要使同事对象参与它的管理,就需要在内部维护一个同事对象的列表。

 

l         我们看到,AccountSystem的注册、充值和消费方法会遍历相关的同事对象并且调用它们的专有方法进行操作。在全部操作完成之后,它才会更新自己的账户。

 

class AccountSystem

    {

        private Dictionary<string, int> userBalance = new Dictionary<string, int>();

        private List<GameSystem> gameAreaList = new List<GameSystem>();

 

        public void RegisterGameArea(GameSystem gs)

        {

            gameAreaList.Add(gs);

        }

 

        public void CreateAccount(string userName)

        {

            userBalance.Add(userName, 0);

            foreach (GameSystem gs in gameAreaList)

                gs.CreateAccountSelf(userName);

        }

 

        public void Recharge(string userName, int amount)

        {

            if (userBalance.ContainsKey(userName))

            {

                bool ok = true;

                foreach (GameSystem gs in gameAreaList)

                    ok = gs.RechargeSelf(userName, amount);

                if (ok)

                    userBalance[userName] += amount;

            }

        }

 

        public void Consume(string userName, int amount)

        {

           if (userBalance.ContainsKey(userName))

            {

                bool ok = true;

                foreach (GameSystem gs in gameAreaList)

                    ok = gs.ConsumeSelf(userName, amount);

                if (ok)

                    userBalance[userName] -= amount;

            }

        }

 

        public void QueryBalance(string userName)

        {

            Console.WriteLine("Your balance is " + userBalance[userName]);

        }

    }

 

l         GameSystem是一个抽象同事。充值和消费方法都有两种。一种是给外部调用的充值和消费方法,一种是给外部调用的,另外一种是给AccountSystem调用的。在对外的方法中,GameSystem仅仅是把这个请求转发给中介者,它自己不做实质性的操作,而在xxxSelf()方法中才做真正的充值、消费操作。

 

 abstract class GameSystem

    {

        private AccountSystem accountSystem;

        protected Dictionary<string, int> userBalance = new Dictionary<string, int>();

 

        public GameSystem(AccountSystem accountSystem)

        {

            this.accountSystem = accountSystem;

        }

 

        internal virtual bool CreateAccountSelf(string userName)

        {

            userBalance.Add(userName, 0);

            return true;

        }

 

        internal virtual bool RechargeSelf(string userName, int amount)

        {

            if (userBalance.ContainsKey(userName))

                userBalance[userName] += amount;

            return true;

        }

 

        internal virtual bool ConsumeSelf(string userName, int amount)

        {

            if (userBalance.ContainsKey(userName))

                userBalance[userName] -= amount;

            return true;

        }

 

        public void Recharge(string userName, int amount)

        {

            accountSystem.Recharge(userName, amount);

        }

 

        public void Consume(string userName, int amount)

       {

            accountSystem.Consume(userName, amount);

        }

    }

 

 

l         GameArea1GameArea2是具体同事,调用父类构造方法来和中介者关联。

 class GameArea1 : GameSystem

    {

        public GameArea1(AccountSystem accountSystem) : base(accountSystem) { }

 

        internal override bool CreateAccountSelf(string userName)

        {

            Console.WriteLine(userName + " Registered in GameAre1");

            return base.CreateAccountSelf(userName);

        }

 

        internal override bool RechargeSelf(string userName, int amount)

        {

            base.RechargeSelf(userName, amount);

            Console.WriteLine(userName + "'s amount in GameArea1 is " + userBalance[userName]);

            return true;

        }

 

        internal override bool ConsumeSelf(string userName, int amount)

        {

            base.ConsumeSelf(userName, amount);

            Console.WriteLine(userName + "'s amount in GameArea1 is " + userBalance[userName]);

            return true;

        }

}

 

    class GameArea2 : GameSystem

    {

        public GameArea2(AccountSystem accountSystem) : base(accountSystem) { }

 

        internal override bool CreateAccountSelf(string userName)

        {

            Console.WriteLine(userName + " Registered in GameAre2");

            return base.CreateAccountSelf(userName);

 

        }

 

        internal override bool RechargeSelf(string userName, int amount)

        {

            base.RechargeSelf(userName, amount);

            Console.WriteLine(userName + "'s amount in GameArea2 is " + userBalance[userName]);

            return true;

        }

 

        internal override bool ConsumeSelf(string userName, int amount)

        {

            base.ConsumeSelf(userName, amount);

            Console.WriteLine(userName + "'s amount in GameArea2 is " + userBalance[userName]);

            return true;

        }

   }

总结:

 

      中介者模式的特点就是同事自己意识到它需要和一个中介者关联,而在实际的操作过程中,它们只是负责和中介者通讯并且接受中介者的请求,而不再和其它同事发生直接的关联。

中介者模式和其它设计模式区别:

 

   1:   中介者模式和观察者模式的区别是,前者应用于多对多杂乱交互行为的统筹处理,后者应用于一(多)对多关系的灵活定制。对于本例来说,集中处理后还需要分散处理,那么后半阶段的处理过程可以应用观察者模式。对于前一节的例子来说,如果有多个主体角色和多个观察者进行多对多通讯的话,也可以应用中介者模式来统筹这个多对多的过程

2: 中介者模式和门面模式的区别是,前者的各同事类需要依靠中介者进行双向通讯,应用于子系统之间,而后者的子系统往往不会通过门面去和调用方进行通讯,趋向于单向通讯,应用于子系列和更高层次的系统。本例中就有门面模式和中介者模式的影子。

 

 

posted @ 2009-06-11 08:29  张国涛  阅读(304)  评论(0)    收藏  举报