关于桥接模式
你所在的公司终于决定紧跟掌上娱乐的大潮;现在,老板要考虑游戏跨平台支持方面的问题了。
现在,图形方面需要从逻辑代码部分完全分离,这样就可以方便移植到各种平台;好吧,现在整个系统将被无情地划分为两个层次结构:逻辑代码层与界面层。
在这个结构下,无论是逻辑代码层或界面层的实现有变化,都不会影响到对方,就像它们之间没有任何关系似的。但实际情况是,它们不可能没有关系,一个游戏必须的逻辑运算,当然也不能缺少了漂亮的界面。
牛郎织女还有鹊桥呢,我们当然也可以在逻辑代码与界面之间搭座桥;现在,我们就开始使用桥接模式建大桥了。
桥接模式(Bridge Pattern)的定义是这样的:将抽象部分与它的实现部分分离,使它们者可以独立地变化。
在我们例子中,抽象部分部分可以理解为逻辑代码层,这是因为这些代码很辛苦地在后台运行,而用户只看到界面层显示的结果;而界面层就是实现部分,它是用户最终看到的东西。
现在,做图形的团队给出了界面层的接口,它的定义是这样的:
''图形界面接口 Public Interface IGameGraphic Sub DrawUnit(ByVal unit As IUnit) End Interface |
(项目:BridgePatternDemo 文件:Interfaces.vb)
由于我们游戏首先在Windows平台发行,所以,我们首先使用了CWinGG类作为图形界面,它的定义如下:
''Windows平台图形界面 Public Class CWinGG Implements IGameGraphic Public Sub DrawUnit(ByVal unit As IUnit) Implements IGameGraphic.DrawUnit Console.WriteLine(">>>>Windows平台界面") Console.WriteLine("<{0}>显示在位置({1},{2})", _ unit.Name,unit.CurX,unit.CurY) End Sub End Class |
(项目:BridgePatternDemo 文件:GameGraphics.vb)
就这么简单,因为你是游戏单位团队的,所以,只需要提供游戏单位相关的信息就可以了,当图形团队创建了一个平台的游戏图形界面类(基于IGameGraphic接口)后,你就可以通过调用DrawUnit()方法显示这个游戏角色了。现在的问题是,在我们的逻辑代码这边,如何把桥连上。
一般的做法是,在抽象层这边创建一个桥的实现者(Implementor);这样的话,我们就必须修改IUnit接口的定义,在其中添加一个游戏图形的实现者属性,我就将其命名为GGImplementor。最终,我们的软件架构就是如下图的这个样子:
实现桥接模式
现在,我们就开始修改IUnit接口,它定义修改为:
''游戏角色接口 Public Interface IUnit Property Name As String '名称 Property UnitId As EUnit '游戏类型ID Property Life As Integer '生命值 Property Power As Integer '攻击力 Property State As IState '角色状态 Property CurX As Integer Property CurY As Integer Property GGImplementor As IGameGraphic Sub Move(ByVal x As Integer, ByVal y As Integer) Sub Attack(ByVal x As Integer, ByVal y As Integer) Sub ShowUnit() End Interface |
(项目:BridgePatternDemo 文件:Interfaces.vb)
然后,是CUnit类的修改,代码如下:
''游戏单位基类 Public MustInherit Class CUnit Implements IUnit Protected myGGImplementor As IGameGraphic =New CWinGG Protected myLife, myPower, myCurX, myCurY As Integer ... '当前X坐标 Public Property CurX As Integer Implements IUnit.CurX Get Return myCurX End Get Set(ByVal value As Integer) myCurX = value End Set End Property '当前Y坐标 Public Property CurY As Integer Implements IUnit.CurY Get Return myCurY End Get Set(ByVal value As Integer) myCurY = value End Set End Property '图形界面实现者 Public Property GGImplementor As IGameGraphic Implements IUnit.GGImplementor Get Return myGGImplementor End Get Set(ByVal value As IGameGraphic) myGGImplementor = value End Set End Property '显示游戏单位 Public Sub ShowUnit() Implements IUnit.ShowUnit myGGImplementor.DrawUnit(Me) End Sub End Class |
(项目:BridgePatternDemo 文件:CUnit.vb)
代码中只给出了添加和修改的部分,其它部分请参考上一章的CUnit.vb文件。
现在,我们又接到通知,图形团队又实现了Android平台的图片界面类,它的定义是这样的:
''Android平台图形界面 Public Class CAndroidGG Implements IGameGraphic Public Sub DrawUnit(ByVal unit As IUnit) Implements IGameGraphic.DrawUnit Console.WriteLine(">>>>Android平台界面") Console.WriteLine("<{0}>显示在位置({1},{2})", _ unit.Name, unit.CurX, unit.CurY) End Sub End Class |
(项目:BridgePatternDemo 文件:GameGraphics.vb)
现在,我们就测试一下游戏单位在两种界面下显示的情况,代码如下:
Module Module1 Sub Main() Dim GuanYu As New CGuanYu GuanYu.AddUnit(New CWeapon2) GuanYu.CurX = 100 GuanYu.CurY = 100 ' GuanYu.ShowUnit() Console.WriteLine() '更换平台界面 GuanYu.GGImplementor = New CAndroidGG GuanYu.ShowUnit() ' Console.ReadLine() End Sub End Module |
(项目:BridgePatternDemo 文件:Module1.vb)
当我们创建角色关羽时,默认的平台是Windows(CWinGG),在显示此角色后,我们将平台设置为Android(CAndroidGG)。此代码的运行结果如下图:
在这个架构下,我们的项目可以独立的修改游戏逻辑代码或图形代码,只要它们的接口(桥)不变,就可以很方便的进行多个平台的项目组合;当然,这些工作还需要平台的支持。
小结
突然看上去,桥接模式可能与前面使用的策略模式中的“组合”差不多,但它们还是有区别的。我们可以看到,在桥接模式中,两个层次是平行的关系,它们可独立修改各自的实现,然后通过桥接进行配合工作;而策略模式中的“组合”只是将相同标准的但不同类型的“零件”灵活的组合成不同的对象。想想长江两岸的居民,他们平常谁也影响不了谁,但有了长江大桥,他们就可以进行各种交流。
别忘了还有鹊桥相会,可不仅仅是牛郎会织女这么简单哦,它还给中国带来新的节日经济增长点;看来,桥的作用还是很大的。
出自:http://www.caohuayu.com/books/B0003/B0003.aspx