无废话C#设计模式之二十: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 { class Program { static void Main(string[] args) { AccountSystem accountSystem = new AccountSystem(); GameSystem gameArea1 = new GameArea1(accountSystem); GameSystem gameArea2 = new GameArea2(accountSystem); accountSystem.RegisterGameArea(gameArea1); accountSystem.RegisterGameArea(gameArea2); string userName = "aaa"; accountSystem.CreateAccount(userName); gameArea1.Recharge(userName, 200); gameArea2.Consume(userName, 50); accountSystem.QueryBalance(userName); } }
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]); } } 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); } }
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; } <span lan 发表评论
最新评论
|
评论