南充网站建设服务商,制作网站的步骤是什么,石家庄做网站制作公司,常州市网站建设公司概述
现在有一个需求#xff0c;需要创建不同的图形#xff0c;并且每个图形都有可能会有不同的颜色。我们可以利用继承的方式来设计类的关系#xff1a;
我们可以发现有很多的类#xff0c;假如我们再增加一个形状或再增加一种颜色#xff0c;就需要创建更多的类。
试…概述
现在有一个需求需要创建不同的图形并且每个图形都有可能会有不同的颜色。我们可以利用继承的方式来设计类的关系
我们可以发现有很多的类假如我们再增加一个形状或再增加一种颜色就需要创建更多的类。
试想在一个有多种可能会变化的维度的系统中用继承方式会造成类爆炸扩展起来不灵活。每次在一个维度上新增一个具体实现都要增加多个子类。为了更加灵活的设计系统我们此时可以考虑使用桥接模式。
定义
将抽象与实现分离使它们可以独立变化。它是用组合关系代替继承关系来实现从而降低了抽象和实现这两个可变维度的耦合度。
结构
桥接Bridge模式包含以下主要角色
抽象化Abstraction角色 定义抽象类并包含一个对实现化对象的引用。扩展抽象化Refined Abstraction角色 是抽象化角色的子类实现父类中的业务方法并通过组合关系调用实现化角色中的业务方法。实现化Implementor角色 定义实现化角色的接口供扩展抽象化角色调用。具体实现化Concrete Implementor角色 给出实现化角色接口的具体实现。
案例
【例】视频播放器
需要开发一个跨平台视频播放器可以在不同操作系统平台如Windows、Mac、Linux等上播放多种格式的视频文件常见的视频格式包括RMVB、AVI、WMV等。该播放器包含了两个维度适合使用桥接模式。
类图如下 代码如下
//视频文件
public interface VideoFile {void decode(String fileName);
}//avi文件
public class AVIFile implements VideoFile {public void decode(String fileName) {System.out.println(avi视频文件 fileName);}
}//rmvb文件
public class REVBBFile implements VideoFile {public void decode(String fileName) {System.out.println(rmvb文件 fileName);}
}//操作系统版本
public abstract class OperatingSystemVersion {protected VideoFile videoFile;public OperatingSystemVersion(VideoFile videoFile) {this.videoFile videoFile;}public abstract void play(String fileName);
}//Windows版本
public class Windows extends OperatingSystem {public Windows(VideoFile videoFile) {super(videoFile);}public void play(String fileName) {videoFile.decode(fileName);}
}//mac版本
public class Mac extends OperatingSystemVersion {public Mac(VideoFile videoFile) {super(videoFile);}public void play(String fileName) {videoFile.decode(fileName);}
}//测试类
public class Client {public static void main(String[] args) {OperatingSystem os new Windows(new AVIFile());os.play(战狼3);}
}好处 桥接模式提高了系统的可扩充性在两个变化维度中任意扩展一个维度都不需要修改原有系统。 如如果现在还有一种视频文件类型wmv我们只需要再定义一个类实现VideoFile接口即可其他类不需要发生变化。 实现细节对客户透明
使用场景
当一个类存在两个独立变化的维度且这两个维度都需要进行扩展时。当一个系统不希望使用继承或因为多层次继承导致系统类的个数急剧增加时。当一个系统需要在构件的抽象化角色和具体化角色之间增加更多的灵活性时。避免在两个层次之间建立静态的继承联系通过桥接模式可以使它们在抽象层建立一个关联关系。
JDBC
我们通过 JDBC 驱动的例子来解释一下。JDBC 驱动是桥接模式的经典应用。我们先来看一下如何利用 JDBC 驱动来查询数据库。具体的代码如下所示
Class.forName(com.mysql.jdbc.Driver); // 加载及注册JDBC驱动程序
String url jdbc:mysql://localhost:3306/sample_db?userrootpasswordyour_password;
Connection con DriverManager.getConnection(url);
Statement stmt con.createStatement();
String query select * from test;
ResultSet rs stmt.executeQuery(query);
while (rs.next()) {rs.getString(1);rs.getInt(2);
}如果我们想要把 MySQL 数据库换成 Oracle 数据库只需要把第一行代码中的 com.mysql.jdbc.Driver 换成 oracle.jdbc.driver.OracleDriver 就可以了。当然也有更灵活的实现方式我们可以把需要加载的 Driver 类写到配置文件中当程序启动的时候自动从配置文件中加载这样在切换数据库的时候我们都不需要修改代码只需要修改配置文件就可以了。不管是改代码还是改配置在项目中从一个数据库切换到另一种数据库都只需要改动很少的代码或者完全不需要改动代码那如此优雅的数据库切换是如何实现的呢源码之下无秘密。要弄清楚这个问题我们先从 com.mysql.jdbc.Driver 这个类的代码看起。我摘抄了部分相关代码放到了这里你可以看一下。
package com.mysql.jdbc;
import java.sql.SQLException;public class Driver extends NonRegisteringDriver implements java.sql.Driver {static {try {java.sql.DriverManager.registerDriver(new Driver());} catch (SQLException E) {throw new RuntimeException(Cant register driver!);}}/*** Construct a new driver and register it with DriverManager* throws SQLException if a database error occurs.*/public Driver() throws SQLException {// Required for Class.forName().newInstance()}
}结合 com.mysql.jdbc.Driver 的代码实现我们可以发现当执行 Class.forName(“com.mysql.jdbc.Driver”) 这条语句的时候实际上是做了两件事情。第一件事情是要求 JVM 查找并加载指定的 Driver 类第二件事情是执行该类的静态代码也就是将 MySQL Driver 注册到 DriverManager 类中。
现在我们再来看一下DriverManager 类是干什么用的。具体的代码如下所示。当我们把具体的 Driver 实现类比如com.mysql.jdbc.Driver注册到 DriverManager 之后后续所有对 JDBC 接口的调用都会委派到对具体的 Driver 实现类来执行。而 Driver 实现类都实现了相同的接口java.sql.Driver 这也是可以灵活切换 Driver 的原因。
public class DriverManager {private static final CopyOnWriteArrayListDriverInfo registeredDrivers new CopyOnWriteArrayList();// ...static {loadInitialDrivers();println(JDBC DriverManager initialized);}// ...public static synchronized void registerDriver(java.sql.Driver driver) throws SQLException {if (driver ! null) {registeredDrivers.addIfAbsent(new DriverInfo(driver));} else {throw new NullPointerException();}}public static Connection getConnection(String url, String user, String password)throws SQLException {java.util.Properties info new java.util.Properties();if (user ! null) {info.put(user, user);}if (password ! null) {info.put(password, password);}return (getConnection(url, info, Reflection.getCallerClass()));}// ...
}桥接模式的定义是“将抽象和实现解耦让它们可以独立变化”。那弄懂定义中“抽象”和“实现”两个概念就是理解桥接模式的关键。那在 JDBC 这个例子中什么是“抽象”什么是“实现”呢
实际上JDBC 本身就相当于“抽象”。注意这里所说的“抽象”指的并非“抽象类”或“接口”而是跟具体的数据库无关的、被抽象出来的一套“类库”。具体的 Driver比如com.mysql.jdbc.Driver就相当于“实现”。注意这里所说的“实现”也并非指“接口的实现类”而是跟具体数据库相关的一套“类库”。JDBC 和 Driver 独立开发通过对象之间的组合关系组装在一起。JDBC 的所有逻辑操作最终都委托给 Driver 来执行。