桥接模式(Bridage Pattern)
此模式难度等级为中级,属结构型模式,提出者为Gang Of Four
桥接(Bridge)是用于把抽象化与实现化解耦,使得二者可以独立变化。
它通过提供抽象化和实现化之间的桥接结构,来实现二者的解耦。
意图
将抽象部分与实现部分分离,使它们都可以独立的变化
主要解决:在有多种可能会变化的情况下,用继承会造成类爆炸问题,扩展起来不灵活。
何时使用:实现系统可能有多个角度分类,每一种角度都可能变化。
如何解决:把这种多角度分类分离出来,让它们独立变化,减少它们之间耦合。
关键代码:抽象类依赖实现类。
解释
现实世界中的例子
考虑到你有一件武器具有不同的魔法,假如允许你让不同的武器与不同的魔法混合。你会怎么做?一为每个不同的魔法功能创建多个武器副本,二你会根据需要为武器创建单独的魔法并设置它。桥接模式就是你的第二选择
简而言之
桥接模式是关于更喜欢组合而不是继承。实现细节从一个层次结构派生到另一个具有单独层次结构的对象
维基百科
桥接模式是软件工程中使用的一种设计模式,旨在“将抽象与其实现分离,以便两者可以独立变化”
程序示例
以上面翻译中我们现实世界中的武器例子。如下来建造武器Weapon和魔法Enchantment的组合结构。
首先编写武器组织结构代码:
public interface Weapon {
void wield();
void swing();
void unwield();
Enchantment getEnchantment();
}
public class Sword implements Weapon {
private final Enchantment enchantment;
public Sword(Enchantment enchantment) {
this.enchantment = enchantment;
}
@Override
public void wield() {
LOGGER.info("The sword is wielded.");
enchantment.onActivate();
}
@Override
public void swing() {
LOGGER.info("The sword is swinged.");
enchantment.apply();
}
@Override
public void unwield() {
LOGGER.info("The sword is unwielded.");
enchantment.onDeactivate();
}
@Override
public Enchantment getEnchantment() {
return enchantment;
}
}
public class Hammer implements Weapon {
private final Enchantment enchantment;
public Hammer(Enchantment enchantment) {
this.enchantment = enchantment;
}
@Override
public void wield() {
LOGGER.info("The hammer is wielded.");
enchantment.onActivate();
}
@Override
public void swing() {
LOGGER.info("The hammer is swinged.");
enchantment.apply();
}
@Override
public void unwield() {
LOGGER.info("The hammer is unwielded.");
enchantment.onDeactivate();
}
@Override
public Enchantment getEnchantment() {
return enchantment;
}
}
其次编写分离的魔法组织结构代码:
public interface Enchantment {
void onActivate();
void apply();
void onDeactivate();
}
public class FlyingEnchantment implements Enchantment {
@Override
public void onActivate() {
LOGGER.info("The item begins to glow faintly.");
}
@Override
public void apply() {
LOGGER.info("The item flies and strikes the enemies finally returning to owner's hand.");
}
@Override
public void onDeactivate() {
LOGGER.info("The item's glow fades.");
}
}
public class SoulEatingEnchantment implements Enchantment {
@Override
public void onActivate() {
LOGGER.info("The item spreads bloodlust.");
}
@Override
public void apply() {
LOGGER.info("The item eats the soul of enemies.");
}
@Override
public void onDeactivate() {
LOGGER.info("Bloodlust slowly disappears.");
}
}
最后上面两个组织层次都起作用,自动桥接:
Sword enchantedSword = new Sword(new SoulEatingEnchantment());
enchantedSword.wield();
enchantedSword.swing();
enchantedSword.unwield();
// The sword is wielded.
// The item spreads bloodlust.
// The sword is swinged.
// The item eats the soul of enemies.
// The sword is unwielded.
// Bloodlust slowly disappears.
Hammer hammer = new Hammer(new FlyingEnchantment());
hammer.wield();
hammer.swing();
hammer.unwield();
// The hammer is wielded.
// The item begins to glow faintly.
// The hammer is swinged.
// The item flies and strikes the enemies finally returning to owner's hand.
// The hammer is unwielded.
// The item's glow fades.
应用场景
当遇到如下情况时你应该使用桥接模式:
- 你希望避免抽象与其实现之间的永久绑定。例如,在运行时必须选择或切换实现时,可能会出现这种情况
- 抽象和它们的实现都应该通过子类化来扩展。在这种情况下,Bridge模式允许你组合不同的抽象和实现,并独立地扩展它们
- 一个类存在两个独立变化的维度,且这两个维度都需要进行扩展。
- 抽象中的具体实现发生变化时不应影响客户端;也就是说,客户端他们的代码不应该被重新编译
- 对于那些不希望使用继承或因为多层次继承导致系统类的个数急剧增加的系统,桥接模式尤为适用
- 你想在多个对象之间共享一个实现(也许使用引用计数),这个事实应该对客户端隐藏。一个简单的例子是Coplien的String类,其中多个对象可以共享相同的String表示
写在最后
对于一个类存在两个独立变化的维度,使用桥接模式是再适合不过了。
将抽象和实现放在两个不同的类层次中,使它们可以独立地变化。——《Head First 设计模式》
将类的功能层次结构和实现层次结构相分离,使二者能够独立地变化,并在两者之间搭建桥梁,实现桥接。—— 《图解设计模式》
类的功能层次结构:父类具有基本功能,在子类中增加新的功能;
类的实现层次结构:父类通过声明抽象方法来定义接口,子类通过实现具体方法来实现接口;
桥接模式中有四个角色:
抽象化角色:使用实现者角色提供的接口来定义基本功能接口。
持有实现者角色,并在功能接口中委托给它,起到搭建桥梁的作用;
注意,抽象化角色并不是指它就是一个抽象类,而是指抽象了实现。
改善后的抽象化角色:作为抽象化角色的子类,增加新的功能,也就是增加新的接口(方法);与其构成类的功能层次结构;
实现者角色:提供了用于抽象化角色的接口;它是一个抽象类或者接口。
具体的实现者角色:作为实现者角色的子类,通过实现具体方法来实现接口;与其构成类的实现层次结构。
最后,如果抽象和实现两者做不到独立地变化,就不算桥接模式。
下一篇文章我们将学习结构性模式中的过滤器模式(Filter Pattern)
码字不易,各位看官如果喜欢的话,请给点个喜欢 ️,关注下我,我将努力持续不断的为大家更新