桥接模式核心思想:将抽象与实现分离,让两者可以独立扩展,避免类爆炸。
Abstraction:抽象层,持有实现层的引用(桥)
RefinedAbstraction:扩展抽象
Implementor:实现接口
ConcreteImplementor:具体实现
场景举例:手机品牌(抽象) + 软件(实现) 手机可以运行不同软件,品牌和软件各自新增,不用写大量组合子类。
// 1. 实现接口:软件(Implementor)
interface Software {
void run();
}
// 具体实现:游戏软件
class Game implements Software {
@Override
public void run() {
System.out.println("运行游戏软件");
}
}
// 具体实现:通讯录软件
class AddressBook implements Software {
@Override
public void run() {
System.out.println("运行通讯录软件");
}
}
// 2. 抽象层:手机(Abstraction),持有Software引用【桥接关键点】
abstract class Phone {
protected Software software;
// 注入实现对象,建立桥接
public Phone(Software software) {
this.software = software;
}
public abstract void useSoftware();
}
// 扩展抽象:小米手机(RefinedAbstraction)
class XiaomiPhone extends Phone {
public XiaomiPhone(Software software) {
super(software);
}
@Override
public void useSoftware() {
System.out.print("小米手机:");
software.run();
}
}
// 扩展抽象:华为手机(RefinedAbstraction)
class HuaweiPhone extends Phone {
public HuaweiPhone(Software software) {
super(software);
}
@Override
public void useSoftware() {
System.out.print("华为手机:");
software.run();
}
}
// 客户端测试
public class BridgeDemo {
public static void main(String[] args) {
// 小米手机跑游戏
Phone xiaomiGame = new XiaomiPhone(new Game());
xiaomiGame.useSoftware();
// 小米手机跑通讯录
Phone xiaomiBook = new XiaomiPhone(new AddressBook());
xiaomiBook.useSoftware();
// 华为手机跑游戏
Phone huaweiGame = new HuaweiPhone(new Game());
huaweiGame.useSoftware();
// 华为手机跑通讯录
Phone huaweiBook = new HuaweiPhone(new AddressBook());
huaweiBook.useSoftware();
}
}
输出结果
小米手机:运行游戏软件
小米手机:运行通讯录软件
华为手机:运行游戏软件
华为手机:运行通讯录软件
UML 逻辑关系
抽象层 Phone ──┬── XiaomiPhone
└── HuaweiPhone
↓ 持有引用(桥)
实现层 Software ─┬── Game
└── AddressBook
桥接模式优点
抽象和实现解耦,两边可以独立新增类。新增手机品牌,不用修改软件;新增软件,不用修改手机。
避免继承带来的类爆炸。如果用继承,2 品牌 ×2 软件 =4 个子类,数量会指数上涨。
符合开闭原则。
适用场景
一个类存在两个或多个独立变化维度,希望两个维度可以随意扩展。
不想使用多层继承导致子类膨胀。
扩展测试:新增维度
比如新增软件VideoPlayer,只需要实现Software接口,不需要改动任何 Phone 代码:
class VideoPlayer implements Software{
@Override
public void run() {
System.out.println("运行视频播放器");
}
}
// 使用:new HuaweiPhone(new VideoPlayer()).useSoftware();
对比:如果使用继承方式,每一个【品牌 + 软件】都要新建子类,新增一个软件就要新增 N 个子类。
本文原创作者:易君召,详见:https://www.yijunzhao.cc/about,转载请注明出处。
原文链接
欢迎访问