桥接模式核心概念解析
- 桥接模式 (Bridge Pattern):
- 核心思想是将抽象部分与它的实现部分分离,使它们都可以独立地变化,解耦两个独立变化的维度;
- 可以用一个通俗的比喻理解:把 “功能抽象” (比如 “手机”) 和 “功能实现” (比如 “操作系统”) 拆成两个独立的维度,二者通过 “桥” 连接,各自扩展互不影响;比如手机可以按品牌 (抽象维度:小米、苹果) 分类,也可以按系统 (实现维度:Android、iOS) 分类,桥接模式能避免品牌和系统组合产生的类爆炸问题 (如小米 Android、小米 iOS、苹果 Android、苹果 iOS);
- 类图:
- 实现代码:
// ===================== 实现化(Implementor):支付方式接口 ===================== interface PayImplementor { // 支付核心实现方法(对应类图的 operationImpl) pay(amount: number): string; } // ===================== 具体实现化(ConcreteImplementor) ===================== // 微信支付(具体实现1) class WechatPay implements PayImplementor { pay(amount: number): string { return `微信支付${amount}元`; } } // 支付宝支付(具体实现2) class Alipay implements PayImplementor { pay(amount: number): string { return `支付宝支付${amount}元`; } } // ===================== 抽象化(Abstraction):外卖平台抽象类 ===================== abstract class FoodPlatform { // 持有实现化角色的引用(桥接的核心:连接抽象和实现) protected payImplementor: PayImplementor; constructor(payImplementor: PayImplementor) { this.payImplementor = payImplementor; } // 抽象方法:下单支付(对应类图的 operation) abstract orderPay(amount: number): string; } // ===================== 扩展抽象化(RefinedAbstraction) ===================== // 美团外卖(扩展抽象1) class Meituan extends FoodPlatform { orderPay(amount: number): string { // 调用实现层的方法,抽象层和实现层通过桥接交互 return `美团外卖下单:${this.payImplementor.pay(amount)}`; } } // 饿了么外卖(扩展抽象2) class Eleme extends FoodPlatform { orderPay(amount: number): string { return `饿了么下单:${this.payImplementor.pay(amount)}`; } } // ===================== 测试 Demo(验证效果) ===================== // 场景1:美团外卖 + 微信支付 const wechatPay = new WechatPay(); const meituan = new Meituan(wechatPay); console.log(meituan.orderPay(30)); // 输出:美团外卖下单:微信支付30元 // 场景2:饿了么 + 支付宝 const alipay = new Alipay(); const eleme = new Eleme(alipay); console.log(eleme.orderPay(50)); // 输出:饿了么下单:支付宝支付50元 // 场景3:动态切换支付方式(桥接模式的优势:独立扩展) meituan.payImplementor = alipay; console.log(meituan.orderPay(20)); // 输出:美团外卖下单:支付宝支付20元
常用使用场景
UI 组件(抽象层)+ 主题样式(实现层)
-
场景说明:前端开发中,按钮、卡片等 UI 组件 (维度 1) 需要适配不同主题 (亮色 / 暗色 / 复古,维度 2),若用继承会产生 “PrimaryButton+LightTheme”、“PrimaryButton+DarkTheme” 等大量子类,桥接模式可解耦组件和主题;
-
核心思路
- 抽象层 (Abstraction):UI 组件基类 (Button/Card);
- 扩展抽象层 (RefinedAbstraction):具体组件 (PrimaryButton/SecondaryButton);
- 实现层 (Implementor):主题接口 (Theme);
- 具体实现层 (ConcreteImplementor):亮色 / 暗色主题;
// ===================== 实现层:主题接口(Implementor) ===================== interface Theme { // 获取主题样式(核心实现方法) getStyle(): { background: string; color: string }; } // 具体实现1:亮色主题 class LightTheme implements Theme { getStyle() { return { background: "#ffffff", color: "#333333" }; } } // 具体实现2:暗色主题 class DarkTheme implements Theme { getStyle() { return { background: "#333333", color: "#ffffff" }; } } // ===================== 抽象层:UI组件基类(Abstraction) ===================== abstract class UIComponent { protected theme: Theme; constructor(theme: Theme) { this.theme = theme; } // 抽象方法:渲染组件 abstract render(): string; } // ===================== 扩展抽象层:具体UI组件 ===================== // 主要按钮(扩展抽象1) class PrimaryButton extends UIComponent { render(): string { const style = this.theme.getStyle(); return `主要按钮:背景${style.background},文字${style.color}`; } } // 次要按钮(扩展抽象2) class SecondaryButton extends UIComponent { render(): string { const style = this.theme.getStyle(); return `次要按钮:背景${style.background},文字${style.color}`; } } // ===================== 效果验证 ===================== // 场景1:主要按钮 + 亮色主题 const lightTheme = new LightTheme(); const primaryLightBtn = new PrimaryButton(lightTheme); console.log(primaryLightBtn.render()); // 输出:主要按钮:背景#ffffff,文字#333333 // 场景2:次要按钮 + 暗色主题 const darkTheme = new DarkTheme(); const secondaryDarkBtn = new SecondaryButton(darkTheme); console.log(secondaryDarkBtn.render()); // 输出:次要按钮:背景#333333,文字#ffffff // 场景3:动态切换主题(桥接优势:独立扩展) primaryLightBtn.theme = darkTheme; console.log(primaryLightBtn.render()); // 输出:主要按钮:背景#333333,文字#ffffff
图表组件(抽象层)+ 数据源(实现层)
-
场景说明:折线图、柱状图等图表 (维度 1) 需要对接不同数据源 (本地数据 / 接口数据 / 缓存数据,维度 2),桥接模式可让图表逻辑和数据获取逻辑独立扩展;
-
核心思路:
- 抽象层:图表基类 (Chart);
- 扩展抽象层:折线图 / 柱状图;
- 实现层:数据源接口 (DataSource);
- 具体实现层:本地数据源 / 接口数据源;
// ===================== 实现层:数据源接口 ===================== interface DataSource { // 获取图表数据 fetchData(): number[]; } // 具体实现1:本地数据源 class LocalDataSource implements DataSource { fetchData(): number[] { return [10, 20, 30, 40]; // 模拟本地静态数据 } } // 具体实现2:接口数据源(模拟异步请求) class ApiDataSource implements DataSource { fetchData(): number[] { // 实际开发中是异步请求,这里简化为同步返回 console.log("从接口获取数据..."); return [50, 60, 70, 80]; } } // ===================== 抽象层:图表基类 ===================== abstract class Chart { protected dataSource: DataSource; constructor(dataSource: DataSource) { this.dataSource = dataSource; } // 抽象方法:渲染图表 abstract render(): string; } // ===================== 扩展抽象层:具体图表 ===================== // 折线图 class LineChart extends Chart { render(): string { const data = this.dataSource.fetchData(); return `折线图渲染数据:${data.join(", ")}`; } } // 柱状图 class BarChart extends Chart { render(): string { const data = this.dataSource.fetchData(); return `柱状图渲染数据:${data.join(", ")}`; } } // ===================== 效果验证 ===================== // 场景1:折线图 + 本地数据源 const localData = new LocalDataSource(); const lineChart = new LineChart(localData); console.log(lineChart.render()); // 输出:折线图渲染数据:10, 20, 30, 40 // 场景2:柱状图 + 接口数据源 const apiData = new ApiDataSource(); const barChart = new BarChart(apiData); console.log(barChart.render()); // 输出:从接口获取数据... 柱状图渲染数据:50, 60, 70, 80
请求封装(抽象层)+ 适配器(实现层)
-
场景说明:业务请求 (用户请求 / 订单请求,维度 1) 需要适配不同请求库 (Axios/Fetch/ 小程序 wx.request,维度 2),桥接模式可让业务逻辑与底层请求库解耦;
-
核心思路:
- 抽象层:业务请求基类 (BusinessRequest);
- 扩展抽象层:用户请求 / 订单请求;
- 实现层:请求适配器接口 (RequestAdapter);
- 具体实现层:Axios 适配器 / Fetch 适配器;
// ===================== 实现层:请求适配器接口 ===================== interface RequestAdapter { // 发送请求(通用参数) request(url: string, method: string): Promise<string>; } // 具体实现1:Axios适配器 class AxiosAdapter implements RequestAdapter { async request(url: string, method: string): Promise<string> { // 模拟Axios请求 return Promise.resolve(`Axios ${method} ${url} 响应:成功`); } } // 具体实现2:Fetch适配器 class FetchAdapter implements RequestAdapter { async request(url: string, method: string): Promise<string> { // 模拟Fetch请求 return Promise.resolve(`Fetch ${method} ${url} 响应:成功`); } } // ===================== 抽象层:业务请求基类 ===================== abstract class BusinessRequest { protected adapter: RequestAdapter; protected baseUrl = "https://api.example.com"; constructor(adapter: RequestAdapter) { this.adapter = adapter; } // 抽象方法:发送业务请求 abstract send(): Promise<string>; } // ===================== 扩展抽象层:具体业务请求 ===================== // 用户请求 class UserRequest extends BusinessRequest { async send(): Promise<string> { return this.adapter.request(`${this.baseUrl}/user`, "GET"); } } // 订单请求 class OrderRequest extends BusinessRequest { async send(): Promise<string> { return this.adapter.request(`${this.baseUrl}/order`, "POST"); } } // ===================== 效果验证 ===================== // 场景1:用户请求 + Axios适配器 const axiosAdapter = new AxiosAdapter(); const userRequest = new UserRequest(axiosAdapter); userRequest.send().then(res => console.log(res)); // 输出:Axios GET https://api.example.com/user 响应:成功 // 场景2:订单请求 + Fetch适配器 const fetchAdapter = new FetchAdapter(); const orderRequest = new OrderRequest(fetchAdapter); orderRequest.send().then(res => console.log(res)); // 输出:Fetch POST https://api.example.com/order 响应:成功
桥接模式的优点与缺点
-
优点:
- 分离接口和实现:抽象和实现可以独立扩展;
- 提高可扩展性:可以独立扩展抽象层次和实现层次;
- 对客户端隐藏实现细节:客户端只需关心抽象部分;
-
缺点:
- 增加复杂度:需要多定义一组接口和类;
- 设计难度增加:需要正确识别抽象和实现两个维度;
与其他模式的关系
-
抽象工厂模式:可以结合桥接模式,用于创建具体的实现;
-
适配器模式:用于适配已有接口,而桥接模式用于分离抽象和实现;
-
策略模式:桥接模式的实现部分类似于策略模式;
原型模式(创建型模式)
上一篇