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

设计模式-桥接模式 - MaC

什么是桥接模式?

桥接模式是一种结构型设计模式,它将抽象部分与实现部分分离,使它们可以独立变化。桥接模式通过组合关系代替继承关系,降低了抽象和实现这两个可变维度的耦合度。
桥接模式包含以下角色:

  • 抽象部分(Abstract):定义抽象接口,通常包含指向实现部分的引用
  • 细化抽象部分(Refined Abstract):扩展抽象部分,提供更具体的实现
  • 实现部分(Implementor):定义实现接口,通常是一个接口或抽象类
  • 具体实现部分(Concrete Implementor):实现Implementor接口的具体实现

桥接模式的优缺点

优点:

  • 分离抽象和实现:抽象部分和实现部分可以独立开发和变化
  • 提高可扩展性:可以独立地扩展抽象部分和实现部分
    符合开闭原则:新增抽象或实现时无需修改现有代码
  • 隐藏实现细节:客户端不需要关心具体实现细节
  • 减少子类数量:避免了多重继承导致的子类爆炸问题

缺点:

  • 增加系统复杂度:需要正确识别系统中两个独立变化的维度
  • 设计难度增加:需要在设计阶段就识别出抽象和实现部分
  • 可能影响性能:通过组合方式实现功能,可能比直接继承方式稍慢

什么场景下使用桥接模式

  1. 不希望在抽象和实现部分之间有固定的绑定关系
  2. 类的抽象和实现都应该可以通过生成子类的方法加以扩充
  3. 对一个抽象的实现部分的修改应对客户不产生影响
  4. 想在带有不同抽象接口的多个对象之间共享实现
  5. 想在运行时刻切换不同的实现

代码举例

其实在实际开发当中能用到的桥接模式还说很多的,比如spring中的jdbc,日志框架等一些经典的开源框架中都有用到。我认为想真正在实际开发当中用到这些设计模式代码到例子必须在一个功能下举例更好,下面简单以日志输出举例

/ 实现部分接口 - 日志输出API
public interface LogAppender {void append(String level, String message, Throwable throwable);void append(String level, String message);void flush();void close();
}// 具体实现部分 - 控制台日志输出
public class ConsoleLogAppender implements LogAppender {private PrintWriter writer;public ConsoleLogAppender() {this.writer = new PrintWriter(System.out, true);}@Overridepublic void append(String level, String message, Throwable throwable) {writer.printf("[%s] %s%n", level, message);if (throwable != null) {throwable.printStackTrace(writer);}writer.flush();}@Overridepublic void append(String level, String message) {append(level, message, null);}@Overridepublic void flush() {writer.flush();}@Overridepublic void close() {writer.close();}
}// 具体实现部分 - 文件日志输出
public class FileLogAppender implements LogAppender {private PrintWriter writer;private String fileName;public FileLogAppender(String fileName) {this.fileName = fileName;try {this.writer = new PrintWriter(new FileWriter(fileName, true), true);} catch (IOException e) {throw new RuntimeException("无法创建日志文件: " + fileName, e);}}@Overridepublic void append(String level, String message, Throwable throwable) {String timestamp = new java.text.SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new java.util.Date());writer.printf("[%s] [%s] %s%n", timestamp, level, message);if (throwable != null) {throwable.printStackTrace(writer);}}@Overridepublic void append(String level, String message) {append(level, message, null);}@Overridepublic void flush() {writer.flush();}@Overridepublic void close() {writer.close();}public String getFileName() {return fileName;}
}// 具体实现部分 - 数据库日志输出
public class DatabaseLogAppender implements LogAppender {private DataSource dataSource;private String tableName;public DatabaseLogAppender(DataSource dataSource, String tableName) {this.dataSource = dataSource;this.tableName = tableName;}@Overridepublic void append(String level, String message, Throwable throwable) {String sql = "INSERT INTO " + tableName + " (log_level, log_message, log_time, throwable_info) VALUES (?, ?, ?, ?)";try (Connection conn = dataSource.getConnection();PreparedStatement stmt = conn.prepareStatement(sql)) {stmt.setString(1, level);stmt.setString(2, message);stmt.setTimestamp(3, new Timestamp(System.currentTimeMillis()));stmt.setString(4, throwable != null ? throwable.toString() : null);stmt.executeUpdate();} catch (SQLException e) {// 为避免循环日志,这里简单处理System.err.println("数据库日志写入失败: " + e.getMessage());}}@Overridepublic void append(String level, String message) {append(level, message, null);}@Overridepublic void flush() {// 数据库操作自动提交,无需特殊处理}@Overridepublic void close() {// 数据库连接由连接池管理,这里不关闭}
}// 抽象部分 - 日志记录器
public abstract class Logger {protected LogAppender appender;protected String name;protected boolean enabled;public Logger(String name, LogAppender appender) {this.name = name;this.appender = appender;this.enabled = true;}public abstract void debug(String message);public abstract void info(String message);public abstract void warn(String message);public abstract void error(String message);public abstract void error(String message, Throwable throwable);public void setEnabled(boolean enabled) {this.enabled = enabled;}public boolean isEnabled() {return enabled;}protected void log(String level, String message) {if (enabled) {appender.append(level, String.format("[%s] %s", name, message));}}protected void log(String level, String message, Throwable throwable) {if (enabled) {appender.append(level, String.format("[%s] %s", name, message), throwable);}}
}// 细化抽象部分 - 简单日志记录器
public class SimpleLogger extends Logger {public SimpleLogger(String name, LogAppender appender) {super(name, appender);}@Overridepublic void debug(String message) {log("DEBUG", message);}@Overridepublic void info(String message) {log("INFO", message);}@Overridepublic void warn(String message) {log("WARN", message);}@Overridepublic void error(String message) {log("ERROR", message);}@Overridepublic void error(String message, Throwable throwable) {log("ERROR", message, throwable);}
}// 细化抽象部分 - 带级别的日志记录器
public class LevelLogger extends Logger {public enum LogLevel {DEBUG(0), INFO(1), WARN(2), ERROR(3);private final int level;LogLevel(int level) {this.level = level;}public int getLevel() {return level;}}private LogLevel currentLevel = LogLevel.INFO;public LevelLogger(String name, LogAppender appender) {super(name, appender);}public void setLevel(LogLevel level) {this.currentLevel = level;}@Overridepublic void debug(String message) {if (currentLevel.getLevel() <= LogLevel.DEBUG.getLevel()) {log("DEBUG", message);}}@Overridepublic void info(String message) {if (currentLevel.getLevel() <= LogLevel.INFO.getLevel()) {log("INFO", message);}}@Overridepublic void warn(String message) {if (currentLevel.getLevel() <= LogLevel.WARN.getLevel()) {log("WARN", message);}}@Overridepublic void error(String message) {if (currentLevel.getLevel() <= LogLevel.ERROR.getLevel()) {log("ERROR", message);}}@Overridepublic void error(String message, Throwable throwable) {if (currentLevel.getLevel() <= LogLevel.ERROR.getLevel()) {log("ERROR", message, throwable);}}
}// 工具类工厂 - 简化使用
public class LoggerFactory {private static final Map<String, Logger> loggerCache = new ConcurrentHashMap<>();public static Logger getLogger(String name, String appenderType, Object... config) {String key = name + "_" + appenderType;return loggerCache.computeIfAbsent(key, k -> createLogger(name, appenderType, config));}public static Logger getLogger(Class<?> clazz, String appenderType, Object... config) {return getLogger(clazz.getName(), appenderType, config);}private static Logger createLogger(String name, String appenderType, Object... config) {LogAppender appender = createAppender(appenderType, config);// 可以根据需要选择不同类型的Loggerreturn new LevelLogger(name, appender);}private static LogAppender createAppender(String appenderType, Object... config) {switch (appenderType.toLowerCase()) {case "console":return new ConsoleLogAppender();case "file":if (config.length > 0 && config[0] instanceof String) {return new FileLogAppender((String) config[0]);} else {return new FileLogAppender("application.log");}case "database":if (config.length >= 2 && config[0] instanceof DataSource && config[1] instanceof String) {return new DatabaseLogAppender((DataSource) config[0], (String) config[1]);} else {throw new IllegalArgumentException("数据库日志需要DataSource和表名参数");}default:return new ConsoleLogAppender();}}
}// 客户端使用示例
public class LoggerDemo {public static void main(String[] args) {// 开发环境使用控制台日志Logger consoleLogger = LoggerFactory.getLogger("UserService", "console");consoleLogger.info("用户服务启动");consoleLogger.debug("调试信息");consoleLogger.error("发生错误", new RuntimeException("测试异常"));// 生产环境使用文件日志Logger fileLogger = LoggerFactory.getLogger("OrderService", "file", "order-service.log");fileLogger.info("订单服务启动");fileLogger.warn("订单处理警告");// 审计日志使用数据库存储DataSource dataSource = ... // 获取数据源Logger dbLogger = LoggerFactory.getLogger("AuditService", "database", dataSource, "audit_log");dbLogger.info("用户登录审计");// 测试日志级别控制LevelLogger levelLogger = (LevelLogger) LoggerFactory.getLogger("TestService", "console");levelLogger.setLevel(LevelLogger.LogLevel.WARN);levelLogger.debug("这条DEBUG日志不会输出");levelLogger.info("这条INFO日志不会输出");levelLogger.warn("这条WARN日志会输出");levelLogger.error("这条ERROR日志会输出");}
}
http://www.wxhsa.cn/company.asp?id=1409

相关文章:

  • linux环境docker离线镜像elasticsearch-7.17.3镜像资源
  • Python 降序排序:轻松搞定列表、字典和自定义对象
  • 第02周 预习、实验与作业:Java基础语法2、面向对象入门
  • part 4
  • systemctl的service脚本写法
  • 9月份美联储的降息利好
  • 口胡记录
  • Day16内存分析及初始化
  • leveldb源码分析 #1 Slice WriteBatch WriteBatchInternal 【work记录】
  • 欧拉安装
  • 2025实测:6款主流公众号编辑器大比拼,解决你的排版难题!
  • 设计模式-适配器模式 - MaC
  • devc学C语言
  • HarmonyOS 5.1手势事件详解
  • Vue3项目中集成AI对话功能的实战经验分享
  • gulimall出现服务间调用org.springframework.cloud.netflix.ribbon.RibbonLoadBalancerClient.choose 问题
  • Java02课前问题列表
  • 达梦数据库安装和使用
  • CSP 赛前周记
  • Ubuntu 界面变为 Mac
  • Day16对数组的基本认识
  • PVE9环境下飞牛OS安装vGPU驱动
  • 02020304 .NET Core核心基础组件04-配置系统、Json文件配置、选项方式读取、扁平化环境变量其它配置源
  • md格式
  • CSP-S模拟20
  • 第7篇、Kafka Streams 与 Connect:企业级实时数据处理架构实践指南
  • Day16编写一个计算机程序
  • 迷宫最短路径
  • 千靶日记-0003
  • COMSOL 6.3 下载+安装教程+激活教程:一站式下载安装激活操作说明