当前位置: 首页 > ds >正文

模式组合应用-桥接模式(一)

写在前面

Hello,我是易元,这篇文章是我学习设计模式时的笔记和心得体会。如果其中有错误,欢迎大家留言指正!

文章为设计模式间的组合使用,涉及代码较多,个人觉得熟能生巧,希望自己能从中学习到新的思维、新的灵感,希望大家也能有所收获。


模式回顾

定义

桥接模式是一种结构型涉及模式,它旨在将抽象部分与其实现部分分离,使得它们可以独立的变化。 桥接模式通过组合而非继承的方式,将抽象和实现解耦,从而解决了传统继承在多维度变化时导致的类爆炸问题。

角色

  • 抽象化(Abstraction): 定义抽象类的接口,并维护一个指向实现化对象的引用。通常是一个抽象类,持有 实现化的引用。

  • 扩展抽象化(Refined Abstraction): 是抽象化角色的具体实现,它扩展了抽象化接口,并可以调用实现化对象的具体方法。

  • 实现化(Implementor): 定义实现类的接口,这个接口不一定要与抽象化接口完全一致,它只给出实现化角色的基本操作。通常是一个接口。

  • 具体实现化(Concrete Implementor): 是实现化角色的具体实现,实现了接口定义的操作。

思考方向

  1. 是否存在多维度变化: 如果一个类存在两个或多个独立变化的维度,并且这些维度都需要独立扩展。

  2. 避免类爆炸: 当使用继承会导致类的数量急剧增加时,桥接模式可以有效的减少类的数量,简化系统结构。

  3. 抽象与实现是都需要独立演化: 如果抽象和实现需要独立的进行修改、扩展或重用。

  4. 运行时切换实现: 桥接模式允许在运行时动态的切换实现,因为抽象和实现是通过组合而不是继承来关联的。

桥接模式代码练习

案例

假设需要开发一个消息通知模块,需满足两个基本要求,第一个要求包含多种发送方式(如: 短信、邮件、APP内部推送),第二个要求是需要区分消息的类型(不同的类型展现形式也不同,如:紧急通知,普通通知、错误消息等)。

案例分析

以桥接模式为代码开发的主要框架,以消息的类型为抽象部分,发送的方式为实现部分,使得两个维度的变化相对独立。

代码

实现部分接口类
public interface MessageSender {void send(String message);}
  • MessageSender为消息发送接口类,定义实现部分的基本功能,包含一个 send() 方法。

具体实现类
/*** 短信发送*/
public class SmsSender implements MessageSender {@Overridepublic void send(String message) {System.out.println("通过短信发送: " + message);}}/*** 邮件发送*/
public class EmailSender implements MessageSender {@Overridepublic void send(String message) {System.out.println("通过邮件发送: " + message);}}/*** APP推送*/
public class AppPushSender implements MessageSender {@Overridepublic void send(String message) {System.out.println("通过APP推送: " + message);}}
  • SmsSender EmailSender AppPushSender 实现部分的具体实现类,实现了 send() 接口方法,并编写各自发送方式。

抽象部分类
public abstract class AbstractMessage {protected MessageSender messageSender;protected AbstractMessage(MessageSender messageSender) {this.messageSender = messageSender;}public abstract void send(String message);
}
  • AbstractMessage 为抽象部分,抽象类中包含实现部分对象的引用 messageSender,并定义了一个 send() 方法,用于描述消息内容的类型。

抽象部分扩展类
/*** 错误消息*/
public class ErrorMessage extends AbstractMessage {protected ErrorMessage(MessageSender messageSender) {super(messageSender);}@Overridepublic void send(String message) {messageSender.send("[错误]" + message + " 系统需要检查!");}
}/*** 普通消息*/
public class NormalMessage extends AbstractMessage {protected NormalMessage(MessageSender messageSender) {super(messageSender);}@Overridepublic void send(String message) {messageSender.send("[普通]" + message);}}/*** 紧急消息*/
public class UrgentMessage extends AbstractMessage {protected UrgentMessage(MessageSender messageSender) {super(messageSender);}@Overridepublic void send(String message) {System.out.println("[紧急]" + message + "请立即处理!");}
}
  • ErrorMessage NormalMessage UrgentMessage 为抽象部分的扩展类,继承了抽象部分类,并对抽象方法进行实现,定义各自消息类型的格式。

测试类
    @Testpublic void test_send() {MessageSender emailSend = new EmailSender();MessageSender smsSend = new SmsSender();MessageSender appPush = new AppPushSender();AbstractMessage normalEmail = new NormalMessage(emailSend);AbstractMessage urgentSms = new UrgentMessage(smsSend);AbstractMessage errorAppPush = new ErrorMessage(appPush);normalEmail.send("系统升级通知");urgentSms.send("服务器负载过高");errorAppPush.send("数据库连接失败");AbstractMessage normalSms = new NormalMessage(smsSend);normalSms.send("每日报告已生成");}
运行结果
通过邮件发送: [普通]系统升级通知
[紧急]服务器负载过高请立即处理!
通过APP推送: [错误]数据库连接失败 系统需要检查!
通过短信发送: [普通]每日报告已生成Process finished with exit code 0

以上为桥接模式代码应用的复习,加深印象。


桥接模式+策略模式

策略模式: 定义一系列的算法,并将每个算法封装起来,使它们可以相互替换。策略模式让算法独立于使用它的客而变化。

案例

在一个电商平台中,商品详情页需要支持多种展示方式(例如: 简洁视图、详细视图、画廊视图),同时为了应对不同的促销活动,商品价格 的计算方式页需要灵活切换(例如: 原价、打折价、会员价)。

模式职责

  • 桥接模式: 将商品展示方式(抽象部分)与具体的商品数据渲染(实现部分)解耦。

  • 策略模式: 封装不同的价格计算算法,使它们可以相互替换,而不会影响客户端。

具体设计

桥接模式
  • 抽象部分: ProductView 定义商品视图的抽象类,持有对 ProductRenderer 的引用

  • 扩展抽象部分: SimpleProductViewDeatilProductView 等具体商品视图

  • 实现者接口: ProductRenderer 定义商品数据渲染的接口

  • 具体实现者: HtmlProductRendererJsonProductRenderer 具体渲染器。

策略模式
  • 抽象策略: PriceCalculationStrategy 定义价格计算策略的接口

  • 具体策略: OriginalPriceStrategyDiscountPriceStrategyMemberPricesStrategy 具体价格计算策略。

  • 上下文: Product 持有对 PriceCalculationStrategy 的引用,并提供设置策略的方法。

代码

ProductRenderer 接口
/*** 产品修饰类* <p>* 桥接模式-接口部分*/
public interface ProductRenderer {String render(String productData);
}
  • 桥接模式中的 实现部分接口,定义了渲染商品数据的通用接口。

  • render(String productData)方法接受商品数据并返回渲染后的商品介绍。

实现部分具体实现者
/*** Html 商品渲染* <p>* 桥接模式 - 具体实现者*/
public class HtmlProductRenderer implements ProductRenderer {@Overridepublic String render(String productData) {return "<html><body><h1>" + productData + "</h1></body></html>";}
}/*** Json 商品渲染*/
public class JsonProductRenderer implements ProductRenderer {@Overridepublic String render(String productData) {return "{\"product\":\"" + productData + "\"}";}
}
  • 桥接模式中的 具体实现者,分别实现了将商品数据渲染成HTML格式和JSON格式的逻辑。

ProductView 抽象类
public abstract class ProductView {protected ProductRenderer productRenderer;public ProductView(ProductRenderer productRenderer) {this.productRenderer = productRenderer;}public void setProductRenderer(ProductRenderer productRenderer) {this.productRenderer = productRenderer;}public abstract void display(String productData);
}
  • 桥接模式中的抽象部分,维护一个 ProductRenderer 类型的引用,作为连接抽象和实现 的桥梁。

  • setProductRenderer() 方法允许在运行时,动态改变渲染器。

  • display(String productData)抽象方法,由具体的视图类型实现其展示逻辑。

抽象部分扩展类
/*** 详细商品视图* <p>* 桥接模式-扩展抽象部分*/
public class DetailProductView extends ProductView {public DetailProductView(ProductRenderer productRenderer) {super(productRenderer);}@Overridepublic void display(String productData) {System.out.println("Detail View: " + productRenderer.render("Detailed Product Info: " + productData));}}/*** 简单视图扩展* <p>* 桥接模式-扩展抽象部分*/
public class SimpleProductView extends ProductView {public SimpleProductView(ProductRenderer productRenderer) {super(productRenderer);}@Overridepublic void display(String productData) {System.out.println("Simple View: " + productRenderer.render(productData));}
}
  • 桥接模式中的抽象扩展部分,代表了不同复杂度的商品视图。

  • 通过调用 productRenderer.render()方法,将实际渲染工作委托给了具体 ProductRenderer 实现类。

PriceCalculationStrategy(策略抽象类)
/*** 价格计算策略接口* <p>* 策略模式-抽象策略*/
public interface PriceCalculationStrategy {double calculatePrice(double originalPrice);}
  • 定义了价格计算的通用接口,calculatePrice(double originalPrice) 方法接受原始价格并返回计算后的价格。

策略实现类
/*** 原始价格策略* <p>* 策略模式-具体策略*/
public class OriginalPriceStrategy implements PriceCalculationStrategy {@Overridepublic double calculatePrice(double originalPrice) {System.out.println(" ===原始价格=== ");return originalPrice;}
}/*** 会员价格策略* <p>* 策略模式-具体策略*/
public class MemberPriceStrategy implements PriceCalculationStrategy {/*** 会员折扣价*/private double memberDiscount;public MemberPriceStrategy(double memberDiscount) {this.memberDiscount = memberDiscount;}@Overridepublic double calculatePrice(double originalPrice) {System.out.println("使用会员折扣,折扣价格: " + memberDiscount);return originalPrice - memberDiscount;}
}/*** 折扣价格策略* <p>* 策略模式-具体策略*/
public class DiscountPriceStrategy implements PriceCalculationStrategy {/*** 折扣率*/private double discountRate;public DiscountPriceStrategy(double discountRate) {this.discountRate = discountRate;}@Overridepublic double calculatePrice(double originalPrice) {System.out.println("使用折扣计算折扣价格, 折扣率: " + discountRate);return originalPrice * (1 - discountRate);}
}
  • 策略模式中的具体策略类,对calculatePrice() 方法进行实现,填充了各自的计算逻辑和必须的参数。

Product(上下文)
public class Product {private String name;private double originalPrice;private PriceCalculationStrategy priceStrategy;public Product(String name, double originalPrice, PriceCalculationStrategy priceStrategy) {this.name = name;this.originalPrice = originalPrice;this.priceStrategy = priceStrategy;}public void setPriceStrategy(PriceCalculationStrategy priceStrategy) {this.priceStrategy = priceStrategy;}public String getName() {return name;}public double getCalculatedPrice() {return priceStrategy.calculatePrice(originalPrice);}
}
  • 策略模式中的上下文,持有一个 PriceCalculationStrategy 类型的引用,

  • setPriceStrategy()方法允许在运行时动态设置价格计算策略。

  • getCalculatedPrice() 方法 将价格计算的职责委托给当前设置的 PriceCalculationStrategy实现类。

测试类
    @Testpublic void test_bridge_strategy() {Product product = new Product("Smart Watch", 300.0, new OriginalPriceStrategy());SimpleProductView productViewWithBridge = new SimpleProductView(new HtmlProductRenderer());productViewWithBridge.display(product.getName() + " - Original Price: " + product.getCalculatedPrice());product.setPriceStrategy(new DiscountPriceStrategy(0.2));productViewWithBridge.setProductRenderer(new JsonProductRenderer());productViewWithBridge.display(product.getName() + " - Discounted Price: " + product.getCalculatedPrice());System.out.println("\n 应用会员价格策略和HTML渲染器: ");product.setPriceStrategy(new MemberPriceStrategy(25.0));productViewWithBridge.setProductRenderer(new HtmlProductRenderer());productViewWithBridge.display(product.getName() + "- Member Price: " + product.getCalculatedPrice());}
运行结果
 ===原始价格=== 
Simple View: <html><body><h1>Smart Watch - Original Price: 300.0</h1></body></html>
使用折扣计算折扣价格, 折扣率: 0.2
Simple View: {"product":"Smart Watch - Discounted Price: 240.0"}应用会员价格策略和HTML渲染器: 
使用会员折扣,折扣价格: 25.0
Simple View: <html><body><h1>Smart Watch- Member Price: 275.0</h1></body></html>Process finished with exit code 0

组合优势

  • 独立变化: 桥接模式使得商品视图和数据渲染可以独立变化,策略模式使得价格计算算法可以独立变化,两种设计模式的结合,使得系统在多个维度上都具有高度的灵活性和可扩展性。

  • 高度复用: 渲染器和价格策略都可以被不同的商品视图和商品对象复用。

  • 增强扩展性: 增加新的商品视图类型、新的数据渲染方式或新的价格计算策略,都只需要添加新的类,无需修改现有代码。

桥接模式+抽象工厂模式

提供一个接口,用于创建相关或依赖对象的家族,而无需指定它们的具体类。

案例

ERP系统报表功能需求:

  • 报表类型支持:销售报表 库存报表

  • 导出格式支持:PDF Excel

  • 界面主题选项:经典主题 现代主题

模式职责

  • 桥接模式: 将报表生成逻辑与导出格式实现解耦,使得二者能够独立变化。

  • 抽象工厂模式: 创建主题相关的报表和导出格式对象族(经典主题/现代主题)

具体设计

桥接模式
  • 抽象部分: Peport定义报告的结构,并持有一个 ExportFormat 的引用

  • 扩展抽象部分: InventoryReport SalesReport 分别生成库存报表、销售报表内容

  • 实现部分: ExportFormat 定义 export() 方法

  • 具体实现: PDFExport ExcelExport 分别提供基础 PDF 、Excel 导出逻辑

抽象工厂模式
  • 抽象工厂: ThemeFactory 接口,定义了创建产品族的一系列方法

  • 具体工厂: ClassicThemeFactory ModernThemeFactory分别创建经典主题风格 和 现代主题风格的对象

  • 抽象产品: Peport

  • 具体产品: SalesReport InventoryReport PDFExport ExcelExport

代码

ExportFormat
/*** 导出格式* <p>* 桥接模式-实现接口部分*/
public interface ExportFormat {String export(String content);}
  • 桥接模式中的实现者接口,定义了报表导出的方法,export(String content)方法 接受原始内容,返回添加格式后的内容。

具体实现类
/*** PDF导出实现*/
public class PDFExport implements ExportFormat {@Overridepublic String export(String content) {return "生成PDF文档: " + content;}
}/*** Excel 导出实现*/
public class ExcelExport implements ExportFormat {@Overridepublic String export(String content) {return "生成Excel文件: " + content;}}
  • 桥接模式中的具体实现者,分别将接受的内容导出为 PDF 和 Excel

Report
/*** 报表* <p>* 桥接模式-抽象部分*/
public abstract class Report {protected String title;protected List<String> data;protected ExportFormat exportFormat;public Report(ExportFormat exportFormat) {this.exportFormat = exportFormat;}public void setTitle(String title) {this.title = title;}public void setData(List<String> data) {this.data = data;}public abstract String generate();public String export() {return exportFormat.export(generate());}
}
  • 桥接模式中的抽象部分,维护一个ExportFormat 类型的引用。

  • generate() 方法用于获取导出的数据内容

  • export() 方法委托 ExportFormat 实现类 增加导出的格式内容。

抽象部分扩展类
/*** 库存报表*/
public class InventoryReport extends Report {public InventoryReport(ExportFormat exportFormat) {super(exportFormat);this.title = "库存报表";}@Overridepublic String generate() {StringBuilder content = new StringBuilder(title + ":\n");for (String item : data) {content.append(" * ").append(item).append("\n");}return content.toString();}
}/*** 销售报表*/
public class SalesReport extends Report {public SalesReport(ExportFormat exportFormat) {super(exportFormat);this.title = "销售报表";}@Overridepublic String generate() {StringBuilder content = new StringBuilder(title + ":\n");for (String item : data) {content.append(" - ").append(item).append("\n");}return content.toString();}
}
  • 桥接模式中的抽象部分的扩展,分别用于获取库存 、销售 报表数据。

ThemeFactory(抽象工厂类)
/*** 主题对象* <p>* 抽象工厂*/
public interface ThemeFactory {Report createSalesReport();ExportFormat createPDFExport();Report createInventorReport();ExportFormat createExcelExport();
}
  • 抽象工厂模式中的抽象工厂接口,声明创建相关产品对象的接口。

具体工厂类
/*** 经典主题风格* <p>* 具体工厂*/
public class ClassicThemeFactory implements ThemeFactory {@Overridepublic Report createSalesReport() {return new SalesReport(createPDFExport());}@Overridepublic ExportFormat createPDFExport() {return new PDFExport() {@Overridepublic String export(String content) {return "经典主题 - " + super.export(content) + " (带传统边框)";}};}@Overridepublic Report createInventorReport() {return new InventoryReport(createExcelExport());}@Overridepublic ExportFormat createExcelExport() {return new ExcelExport() {@Overridepublic String export(String content) {return "经典主题 - " + super.export(content) + " (使用传统颜色)";}};}
}/*** 现代主题风格* <p>* 具体工厂*/
public class ModernThemeFactory implements ThemeFactory {@Overridepublic Report createSalesReport() {return new SalesReport(createPDFExport());}@Overridepublic ExportFormat createPDFExport() {return new PDFExport() {@Overridepublic String export(String content) {return "现代主题 - " + super.export(content) + " (简约设计)";}};}@Overridepublic Report createInventorReport() {return new InventoryReport(createExcelExport());}@Overridepublic ExportFormat createExcelExport() {return new ExcelExport() {@Overridepublic String export(String content) {return "现代主题 - " + super.export(content) + " (扁平化风格)";}};}
}
  • 抽象工厂模式中的具体工厂类,分别用于创建经典主题和现代主题风格的导出格式对象族,遵循抽象工厂模式,创建统一风格的主题产品。

测试类
    @Testpublic void test_report() {List<String> salesData = Arrays.asList("产品A: 100件", "产品B: 200件", "产品C: 150件");List<String> inventoryData = Arrays.asList("仓库1: 500件", "仓库2: 300件", "仓库3: 450件");System.out.println(" === ERP系统报表模块 ===");System.out.println();// 使用经典主题System.out.println("【经典主题报表】");ThemeFactory classicFactory = new ClassicThemeFactory();Report classicFactorySalesReport = classicFactory.createSalesReport();classicFactorySalesReport.setData(salesData);System.out.println(classicFactorySalesReport.export());System.out.println();// 使用现代主题System.out.println("【现代主题报表】");ThemeFactory modernFactory = new ModernThemeFactory();// 现代订单报表Report modernFactorySalesReport = modernFactory.createSalesReport();modernFactorySalesReport.setData(salesData);System.out.println(modernFactorySalesReport.export());// 现代库存报表Report modernFactoryInventorReport = modernFactory.createInventorReport();modernFactoryInventorReport.setData(inventoryData);System.out.println(modernFactoryInventorReport.export());}
运行结果
 === ERP系统报表模块 ===【经典主题报表】
经典主题 - 生成PDF文档: 销售报表:- 产品A: 100件- 产品B: 200件- 产品C: 150件(带传统边框)【现代主题报表】
现代主题 - 生成PDF文档: 销售报表:- 产品A: 100件- 产品B: 200件- 产品C: 150件(简约设计)
现代主题 - 生成Excel文件: 库存报表:* 仓库1: 500件* 仓库2: 300件* 仓库3: 450件(扁平化风格)Process finished with exit code 0

组合优势

  • 高度的灵活性: 新增报表类型或导出格式时,可以直接新增对应实现类,无需修改现有代码。新增主图变化扩展 ThemeFactory,新增报表逻辑扩展Report,新增导出格式则扩展ExportFormat

  • 风格的统一性: 每个工厂确保创建的对象属于同一个主题

--

未完,下一篇接着写,代码量比较多。

http://www.xdnf.cn/news/18124.html

相关文章:

  • VS Code配置MinGW64编译GLPK(GNU Linear Programming Kit)开源库
  • 一键检测接口是否存活:用 Python/Shell 写个轻量级监控脚本
  • 《MySQL 数据库备份与视图创建全流程:从数据迁移到高效查询实战》
  • 【AI论文】NextStep-1:迈向大规模连续令牌自回归图像生成
  • 2020/12 JLPT听力原文 问题二 2番
  • HackMyVM-Uvalde
  • 高等数学 8.4 空间直线及其方程
  • macOS 中查看当前生效 shell 及配置文件的方法
  • 微服务的编程测评系统12-xxl-job-历史竞赛-竞赛报名
  • 腾讯混元大模型:实现3D打印产品生成的自动化平台
  • python---异常处理
  • 微软Wasm学习-创建一个最简单的c#WebAssembly测试工程
  • ISIS区域内、区域间计算
  • 机器学习——CountVectorizer将文本集合转换为 基于词频的特征矩阵
  • Boost搜索引擎项目(详细思路版)
  • 【3D重建技术】如何基于遥感图像和DEM等数据进行城市级高精度三维重建?
  • 扫地机器人(2025蓝桥杯省A组 H题)
  • AI重构文化基因:从“工具革命”到“生态觉醒”的裂变之路
  • 线性代数之两个宇宙文明关于距离的对话
  • 完整的VOC格式数据增强脚本
  • 狗品种识别数据集:1k+图像,6个类别,yolo标注完整
  • .net印刷线路板进销存PCB材料ERP财务软件库存贸易生产企业管理系统
  • 曲面/线 拟合gnuplot
  • 第四章:大模型(LLM)】06.langchain原理-(5)LangChain Prompt 用法
  • 第七十五章:AI的“思维操控师”:Prompt变动对潜在空间(Latent Space)的影响可视化——看懂AI的“微言大义”!
  • P2169 正则表达式
  • LeetCode 刷题【43. 字符串相乘】
  • 视觉语言模型(VLA)分类方法体系
  • Kotlin-基础语法练习一
  • 代码随想录算法训练营四十三天|图论part01