桥接(Bridge)模式,又名Handle/Body(未找到权威的中文翻译)模式,它将一个类的抽象部分与它的实现部分分离,使它们都可以独立的变化。
举个例子,有这样一个游戏,主角身体里住着三个灵魂,它可以切换成对应的三种形态,来施放不同的技能。三种灵魂定义如下:
public interface ISoul
{
void CastSkill();
}
public class Mage : ISoul
{
public void CastSkill()
{
Console.WriteLine ("Summon a box");
}
}
public class Hunter : ISoul
{
public void CastSkill()
{
Console.WriteLine ("Fire arrow");
}
}
public class Warrior : ISoul
{
public void CastSkill()
{
Console.WriteLine ("Power of Thor");
}
}
但是身体只有一个,所以需要切换形态。貌似我们可以使用switch case语句来完成这个任务:
public enum SoulType
{
Mage,
Hunter,
Warrior,
}
public class Hero
{
private Mage _mage = new Mage();
private Hunter _hunter = new Hunter();
private Warrior _warrior = new Warrior();
private SoulType _soulType = SoulType.Mage;
public void CastSkill()
{
ISoul activeSoul = null;
switch (_soulType) {
case SoulType.Mage:
activeSoul = _mage;
break;
case SoulType.Hunter:
activeSoul = _hunter;
break;
case SoulType.Warrior:
activeSoul = _warrior;
break;
}
activeSoul.CastSkill ();
}
public void ChangeSoul(SoulType soulType)
{
_soulType = soulType;
}
}
使用:
Hero hero = new Hero ();
hero.ChangeSoul (SoulType.Hunter);
hero.CastSkill ();
然而当我们增加一个灵魂的时候,比如牧师(Priest),那么我们就要在修改Hero的CastSkill方法,这显然违背了开闭原则。
这种情况下,可以考虑使用桥接模式:
public class TrineHero
{
private ISoul _soul;
public void CastSkill()
{
_soul.CastSkill ();
}
public void ChangeSoul<T>() where T:ISoul, new()
{
_soul = new T();
}
}
使用:
TrineHero th = new TrineHero ();
th.ChangeSoul<Mage> ();
th.CastSkill ();
这样当我们需要增加牧师的灵魂的时候,只需要实现牧师的类即可:
public class Priest : ISoul
{
public void CastSkill()
{
Console.WriteLine ("Mind control");
}
}
而不需要修改TrineHero这个类,使用:
th.ChangeSoul<Priest> ();
th.CastSkill ();
当然TrineHero的ChangeSoul这个方法有多种多样的实现形式,你可以直接传入一个实例,或者传入字符串(类型名)使用反射实例化对象,这里就不做过多的讨论。
桥接模式在跨平台或者跨工具、跨框架开发的时候,也会经常用到。例如,我们可以创建一个TouchHandle的类,用于封装所有的触摸事件,然后根据不同平台为TouchHandle设置不同的实现对象。可以参考小话设计模式(三)抽象工厂模式。