(一)介绍
桥接模式即将抽象部分与它的实现部分分离开来,使他们都可以独立变化。
桥接模式将继承关系转化成关联关系,它降低了类与类之间的耦合度,减少了系统中类的数量,也减少了代码量。
(二)核心特性
1:继承关系转化成关联关系
2:抽象部分与他的实现部分分离
3:将类的功能层次结构和实现层次结构分离
4:桥接模式的作用就是连接类的功能层次结构和实现层次结构(聚合)
(三)类的功能层次结构和实现层次结构
1:类的功能层次结构
此时我们有一个类,具有一个功能,但是现在我想新增一个功能,不要去修改原类结构,那么此时我我可以通过继承去生成该类的子类,在子类中新增这个功能,此时子类就具有了俩个功能,同理,如果还要添加功能,继续新增子类,这样就呈现出了一种层次增加功能的结构
当要增加新的功能时,我们可以从各个层次的类中找出最符合自己需求的类,然后以它为父类编写子类,并在子类中增加新的功能.这就是类的功能层次结构.
2:类的实现层次结构
编程语言中,抽象类的作用是声明一些抽象方法,定义了接口(API),然后子类负责去实现这些抽象方法.父类的任务是通过声明抽象方法的方式定义接口(API),而子类的任务是实现抽象方法.正是由于父类和子类的这种任务分担,我们才可以编写出具有高可替换的类。而这里其实也存在层次结构,例如:当子类ConcreteClass实现了父类AbstractClass类的抽象方法时,他们之间就构成了一个小小的层次结构.
但是这里类的层次结构并非用于增加功能,也就是说,这种层次结构并非用于方便我们增加新的方法.它的真正作用是帮助我们实现下面这样的任务分担
—父类通过声明抽象方法定义接口(API)
—子类通过实现具体方法来实现接口(API)
这种层次的结构被称为类的实现层次结构
当我们以其他方式实现AbstractClass时,例如要实现一个AnotherConcreteClass时,类的层次结构会稍微发生一些变化
为了一种新的实现方法,我们继承了AbstractClass的子类,并实现了其中的抽象方法,这就是类的实现层次结构
(四)桥接模式结构分析
我们看一下上面的类图,将该类图与前面提及的类的功能层次结构和实现层次结构关联.
左边的部分就是类的功能层次部分,其中Display是一个基类,他提供一个display的功能,而在CountDisplay中继承了该类并且新增自己的一个功能.
右边的部分DisplayImpl是一个抽象类,定义了基本的接口API,该类有一个实现的子类StringDisplayImpl提供了具体的实现.右边整体呈现就是类的实现结构
左右边的关联是通过聚合的方式,在Display中持有DisplayImpl实例属性,通过该属性完成自己具体功能的实现
上面的类图看起来简单,但其实就代表一个完整的桥接模式,如果想要扩展就完全可以新增功能子类和实现.进一步扩展.
(五)代码实例
以下代码实现的展示数据的功能,具体的实现是由DisplayImpl子类完成,CountDisplay增加可以动态显示多次的功能
public class Display {
DisplayImpl displayImpl;
public Display(DisplayImpl displayImpl) {
this.displayImpl = displayImpl;
}
void open() {
displayImpl.rawOpen();
}
void print() {
displayImpl.rawPrint();
}
void close() {
displayImpl.rawClose();
}
void display() {
open();
print();
close();
}
}
public class CountDisplay extends Display {
public CountDisplay(DisplayImpl displayImpl) {
super(displayImpl);
}
void multiDisplay(int times) {
open();
for (int i = 0; i < times; i++) {
print();
}
close();
}
}
public abstract class DisplayImpl {
abstract void rawOpen();
abstract void rawPrint();
abstract void rawClose();
}
public class StringDisplayImpl extends DisplayImpl {
@Override
void rawOpen() {
System.out.println("******启动*****");
}
@Override
void rawPrint() {
System.out.println("******HelloWorld*****");
}
@Override
void rawClose() {
System.out.println("******关闭*****");
}
}
public class Main {
public static void main(String[] args) {
//创建具体实现层
DisplayImpl displayImpl = new StringDisplayImpl();
//将实现层桥接到功能层上
Display display = new CountDisplay(displayImpl);
CountDisplay countDisplay = new CountDisplay(displayImpl);
display.display();
countDisplay.multiDisplay(3);
}
}
(六)角色介绍
Abstract(抽象化)—Display
该角色位于类的功能层次结构的最上层,它使用Implementor角色的方式定义了基本的功能.该角色中保存了Implementor的实例
RefinedAbstraction(改善后的抽象化)—CountDisplay
在Abstraction角色的基础上增加了新功能的角色
Implementor(实现者)—DisplayImpl
该角色位于类的实现层次结构的最上层.定义了用于实现Abstraction角色的接口API的方法
ConcreteImplementor(具体的实现者)—StringDisplayImpl
该角色负责在Implementor角色中定义的接口
桥接者
桥接者对象负责的就是链接功能层次和实现层次,本次代码中桥接者的对象就是Display中的 DisplayImpl displayImpl;实例
(七)扩展
继承是强关联,委托是弱关联
虽然使用继承很容易扩展类,但是类之间也形成了一种强关联关系.例如,在下面的代码中,SomethingGood类是Something的子类,但只要不修改代码,就无法改变这种关系,因此可以说他们之间形成了一种强关联关系:
如果想要很轻松地改变类之间的关系,使用继承就不合适了,因为每次改变类之间关系都需要修改程序。这是,我们可以使用委托来代替继承关系。
上面代码的Display类中使用了委托. Display类的impl字段保存实现的实例,这样,类的任务就发生了转移
也就是说,当其他类要求Display类工作的时候,Display类并非自己工作,而是将工作交给impl。这就是委托。
继承是强关联关系,但委托是弱关联关系。这是因为只有Display类的实例生成时,才与作为参数被传入的类构成关联。例如:在实例程序中,当Main类生成Display类和CountDisplay类的实例时,才将StringDisplayImpl的实例作为参数传递给Display类和CountDisplay类
如果我们不传递StringDisplayImpl类的实例,而是将其他ConcreteImplementor角色的实例传递给Display类和CountDisplay类,就能很容易的改变实现。这时,发生变化的代码只有Main类,Display类和DisplayImpl类则不需要任务修改
(八)应用实例
jdbc 桥接模式
try {
Class.forName("com.mysql.jdbc.Driver");
String url="";
String userName="";
String password="";
Connection conn = DriverManager.getConnection(url, userName, password);
return conn;
} catch (Exception e) {
e.printStackTrace();
}
这里就是用了设计模式中的桥接模式,我们知道不同的数据库自我实现和传输协议不同,java不可能为每种数据库厂商提供其实现,这不符合精简设计的原则,这里java提供了一套统一的接口让各个厂商自己实现,一套接口给程序开发者调用,两者的结合就是经典的桥接模式。
Jdbc 的 Driver接口,如果从桥接模式来看,Driver就是一个接口,下面可以有
MySQL的Driver,Oracle的Driver,这些就可以当做实现接口类
Mysql为例,通过Class.forName(“com.mysql.jdbc.Driver”)类加载的时候执行静态代码块将Driver注册到DriverManager,DriverManager是个Driver容器,管理不同的Driver,这样具体的数据Driver实现就统一交给容器管理,客户端通过DriverManager执行验证连接,获取连接的操作。
static {
try {
DriverManager.registerDriver(new Driver());
} catch (SQLException var1) {
throw new RuntimeException("Can't register driver!");
}
}
转载:https://blog.csdn.net/Octopus21/article/details/104714039