使用频率【3星】
一、概念
桥接(Bridge)是用于把抽象化与实现化解耦,使得二者可以独立变化。这种类型的设计模式属于结构型模式,它通过提供抽象化和实现化之间的桥接结构,来实现二者的解耦。
二、解决问题
在软件系统中,有些类型由于自身的逻辑,它具有两个或多个维度的变化。为了解决这种多维度变化,又不引入复杂度,就可以使用桥接模式。
三、对象
1、抽象类(Abstraction):定义抽象接口,它一般是抽象类而不是接口。该接口中包含实现具体行为、具体特征的Implementor接口。
2、扩充的抽象类(RefinedAbstraction):继承自Abstraction的子类,通常情况下它不再是抽象类而是具体类,它实现了在Abstraction中声明的抽象业务方法,在该对象中可以调用在Implementor中定义的业务方法。
3、实现类(Implementor):定义具体行为,具体特征的应用接口。
4、具体实现类(ConcreteImplementor):实现Implementor。
四、实现代码
1、未使用桥接模式。
一个游戏,主角身体里住着三个灵魂,它可以切换成对应的三种形态,来施放不同的技能。三种灵魂定义如下
public interface ISoul
{
void CastSkill();
}
public class Mage : ISoul
{
public void CastSkill()
{
Debug.Log ("Summon a box");
}
}
public class Hunter : ISoul
{
public void CastSkill()
{
Debug.Log ("Fire arrow");
}
}
public class Warrior : ISoul
{
public void CastSkill()
{
Debug.Log ("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 ();
通过以上代码,我们会发现,再增加一个技能的形态,需要修改Hero的CasterSkill(),不符合开闭原则【可以拓展,但是尽量不修改原有的逻辑】。
2、桥接模式
接口和技能的形态类不修改,可以把Hero修改成以下的类
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 = new TrineHero ();
th.ChangeSoul<Mage> ();
th.CastSkill ();
//切换不同技能
th.ChangeSoul<Priest> ();
th.CastSkill ();
总结:以上 例子当中
抽象类/接口类(Abstraction):TrineHero
扩充的抽象类(RefinedAbstraction):Priest
实现类(Implementor):ISoul
具体实现类(ConcreteImplementor):Mage 三种技能
例子2
using System;
namespace ConsoleApp2
{
class Class1
{
static void Main(string[] args)
{
//白色
Color white = new White();
//正方形
Shape square = new Square();
//白色的正方形
square.SetColor(white);
square.Draw();
//长方形
Shape rectange = new Rectangle();
rectange.SetColor(white);
rectange.Draw();
Console.ReadLine();
}
}
public abstract class Shape
{
public Color color;
public void SetColor(Color color)
{
this.color = color;
}
public abstract void Draw();
}
public class Circle : Shape
{
public override void Draw()
{
color.Bepaint("正方形");
}
}
public class Rectangle : Shape
{
public override void Draw()
{
color.Bepaint("长方形");
}
}
public class Square : Shape
{
public override void Draw()
{
color.Bepaint("正方形");
}
}
public interface Color
{
void Bepaint(string shape);
}
public class White : Color
{
public void Bepaint(string shape)
{
Console.WriteLine("白色的" + shape);
}
}
public class Gray : Color
{
public void Bepaint(string shape)
{
Console.WriteLine("灰色的" + shape);
}
}
public class Black : Color
{
public void Bepaint(string shape)
{
Console.WriteLine("黑色的" + shape);
}
}
}
总结:
抽象类/接口类(Abstraction):Shape
扩充的抽象类(RefinedAbstraction):Circle --继承shape
实现类(Implementor):Color
具体实现类(ConcreteImplementor):Black
说明:两个例子表示的两种桥接的使用情况,第一种是相同类型逻辑的扩展,第二种是两种不同逻辑的扩展
五、优缺点
5.1 优点
- 降低了沿着两个或多个维度扩展时的复杂度,防止类的过度膨胀。
- 桥接模式提高了系统的可扩充性,在两个变化维度中任意扩展一个维度,都不需要修改原有系统。
5.2 缺点
- 桥接模式的引入会增加系统的理解与设计难度,由于聚合关联关系建立在抽象层,要求开发者针对抽象进行设计与编程。
- 桥接模式要求正确识别出系统中两个独立变化的维度,因此其使用范围具有一定的局限性。
六、使用场景
- 当一个对象有多个变化因素时,可以考虑使用桥接模式,通过抽象这些变化因素,将依赖具体实现修改为依赖抽象。
- 当我们期望一个对象的多个变化因素可以动态变化,而且不影响客户端的程序使用时。
- 如果使用继承的实现方案,会导致产生很多子类,任何一个变化因素都需要产生多个类来完成,就要考虑桥接模式。
- 游戏开发中一个武器有多种变化形态,可以考虑使用桥接模式。
设计模式系列博客,主要参考大话设计模式,以及一些博客内容
https://blog.csdn.net/qq826364410/article/details/88143521