模式简介
桥接模式是一种结构型设计模式,用于对抽象部分与实现部分的解耦,使得二者的变化可以相互独立,同时在抽象部分中存储一个对实现部分的引用,建立调用关联。当抽象部分的某个属性或者方法复杂多变时,就可以把它的具体实现部分与该抽象分离,仅保留对实现的引用,从而避免类膨胀的问题,也降低了代码的维护成本。
常见的应用场景:跨平台界面系统、数据库驱动程序、多层存储系统、多媒体应用和电子设备控制等。
模式结构
-
抽象部分(Abstraction): 定义了抽象类的接口,维护了一个指向实现部分的引用。它的结构可以包括抽象方法、成员变量等。
-
扩充抽象部分(Refined Abstraction): 继承自抽象部分,对抽象部分的接口进行扩展,可以实现一些额外的功能。
-
实现部分(Implementor): 定义了实现部分的接口,通常包含了一些基本的操作。这个接口不一定要与抽象部分的接口完全一致,但必须能够被抽象部分调用。
-
具体实现部分(Concrete Implementor): 实现实现部分的接口,提供具体的实现。
工作原理
-
定义抽象部分(Abstraction)和实现部分(Implementor): 首先,你需要定义两个独立的层次结构,一个是抽象部分(Abstraction),一个是实现部分(Implementor)。抽象部分定义了高层次的接口,而实现部分定义了低层次的接口。
-
建立桥梁连接: 在抽象部分中维护一个指向实现部分的引用。这个引用可以是实现部分的接口,使得抽象部分可以调用实现部分的方法。
-
创建具体实现部分: 实现具体的实现部分,即创建实现部分接口的具体实现类。
-
创建抽象部分的具体子类: 创建扩充抽象部分的具体子类,这些子类可以实现抽象部分中定义的抽象方法,并可以扩展一些额外的功能。
-
客户端使用: 在客户端中,可以使用抽象部分的接口来调用相关操作。客户端可以通过抽象部分的具体子类来实例化对象,这些对象可以在运行时选择与特定的实现部分连接。
代码示例(C#)
提示:可在本栏目的资源篇“设计模式代码示例合集”下载所有完整代码资源。
衣服:Clothes.cs
namespace BridgePattern;
// 衣服
abstract class Clothes
{
public string name; // 衣服名称
public string material; // 衣服材质
public Season applicableSeason; // 适用季节
protected ColorDyer colorDyer; // 染色器
public Clothes(string name, string material, Season applicableSeason, ColorDyer colorDyer)
{
this.name = name;
this.material = material;
this.applicableSeason = applicableSeason;
this.colorDyer = colorDyer;
}
// 给模特穿上
public abstract void Dressed(Man man);
}
// 衬衫
class Shirt : Clothes
{
public Shirt(string name, string material, Season applicableSeason, ColorDyer colorDyer) :
base(name, material, applicableSeason, colorDyer)
{ }
public override void Dressed(Man man)
{
Console.WriteLine("------------------------------------");
colorDyer.Dye();
Console.WriteLine(man.name + " is wearing a " + colorDyer.color + " " + name + " made of " + material + " which is suitable for " + applicableSeason + " wear.");
}
}
// 毛衣
class Sweater : Clothes
{
public Sweater(string name, string material, Season applicableSeason, ColorDyer colorDyer) :
base(name, material, applicableSeason, colorDyer)
{ }
public override void Dressed(Man man)
{
Console.WriteLine("------------------------------------");
colorDyer.Dye();
Console.WriteLine(man.name + " is wearing a " + colorDyer.color + " " + name + " made of " + material + " which is suitable for " + applicableSeason + " wear.");
}
}
// 短袖
class ShortSleeve : Clothes
{
public ShortSleeve(string name, string material, Season applicableSeason, ColorDyer colorDyer) :
base(name, material, applicableSeason, colorDyer)
{ }
public override void Dressed(Man man)
{
Console.WriteLine("------------------------------------");
colorDyer.Dye();
Console.WriteLine(man.name + " is wearing a " + colorDyer.color + " " + name + " made of " + material + " which is suitable for " + applicableSeason + " wear.");
}
}
// 夹克
class Jacket : Clothes
{
public Jacket(string name, string material, Season applicableSeason, ColorDyer colorDyer) :
base(name, material, applicableSeason, colorDyer)
{ }
public override void Dressed(Man man)
{
Console.WriteLine("------------------------------------");
colorDyer.Dye();
Console.WriteLine(man.name + " is wearing a " + colorDyer.color + " " + name + " made of " + material + " which is suitable for " + applicableSeason + " wear.");
}
}
染色器:Dyers.cs
namespace BridgePattern;
// 染色器
abstract class ColorDyer
{
public Color color; // 颜色
public ColorDyer(Color color)
{
this.color = color;
}
// 染色
public abstract void Dye();
}
// 红色染色器
class RedDyer : ColorDyer
{
public RedDyer(Color color) : base(color) { }
public override void Dye()
{
Console.WriteLine("The dress is dyed red.");
}
}
// 橙色染色器
class OrangeDyer : ColorDyer
{
public OrangeDyer(Color color) : base(color) { }
public override void Dye()
{
Console.WriteLine("The dress is dyed orange.");
}
}
// 紫色染色器
class PurpleDyer : ColorDyer
{
public PurpleDyer(Color color) : base(color) { }
public override void Dye()
{
Console.WriteLine("The dress is dyed purple.");
}
}
// 白色染色器
class WhiteDyer : ColorDyer
{
public WhiteDyer(Color color) : base(color) { }
public override void Dye()
{
Console.WriteLine("The dress is dyed white.");
}
}
枚举:Enum.cs
namespace BridgePattern;
//季节
enum Season
{
Spring, Summer, Autumn, Winter
}
//颜色
enum Color
{
Red, Blue, Orange, White, Black, Yellow, Green, Purple
}
模特:Man.cs
namespace BridgePattern;
// 男士模特
public class Man
{
public string name; // 名字
public Man(string name)
{
this.name = name;
}
// 行走
public void Walk()
{
Console.WriteLine("The man named " + name + " is walking.");
Thread.Sleep(new Random().Next(3000));
}
}
测试代码:Program.cs
// ************* 18.桥接模式测试 **************
using BridgePattern;
// 找两个模特
Man jojo = new Man("JoJo");
Man kaka = new Man("KaKa");
// 做四种染色器
RedDyer redDyer = new RedDyer(Color.Red);
OrangeDyer orangeDyer = new OrangeDyer(Color.Orange);
PurpleDyer purpleDyer = new PurpleDyer(Color.Purple);
WhiteDyer whiteDyer = new WhiteDyer(Color.White);
// 给四种衣服分别配置一种染色器
Shirt whiteShirt = new Shirt("Shirt", "cotton", Season.Spring, whiteDyer);
Sweater orangeSweater = new Sweater("Sweater", "polyester-fiber", Season.Autumn, orangeDyer);
ShortSleeve purpleShortSleeve = new ShortSleeve("ShortSleeve", "cotton", Season.Summer, purpleDyer);
Jacket redJacket = new Jacket("Jacket", "polyester-fiber and cotton", Season.Winter, redDyer);
// 模特试穿衣服
whiteShirt.Dressed(jojo);
redJacket.Dressed(jojo);
purpleShortSleeve.Dressed(kaka);
orangeSweater.Dressed(kaka);
代码解说
上述代码简单模拟了衣服的染色过程。有Shirt、Sweater、ShortSleeve、Jacket四种类型的衣服,并且每种衣服都可以染Red、Orange、Purple、White四种不同的颜色,这样就会有16种组合,如果每种组合我们都去定义一个类就会出现类爆炸问题。
所以我们就可以采用桥接模式,将衣服与染色器分开,二者分别创建一个基类Clothes和ColorDyer,四种衣服分别继承Clothes基类,四种染色器分别继承ColorDyer。然后我们在Clothes基类中存储一个对ColorDyer的引用,这里就实现了Clothes与ColorDyer的桥接模式,当我们制作一件衣服时需要通过一个染色器进行染色,当我们下次有一种新的衣服或新的染色器时只需要添加一个类即可,就不需要再定义四个类,这就是桥接模式的好处。
如果这篇文章对你有帮助,请给作者点个赞吧!