1.简述
桥接模式即将抽象部分与它的实现部分分离开来,使他们都可以独立变化。桥接模式将继承关系转化成关联关系,它降低了类与类之间的耦合度,减少了系统中类的数量,也减少了代码量。将抽象部分与他的实现部分分离这句话不是很好理解,其实这并不是将抽象类与他的派生类分离,而是抽象类和它的派生类用来实现自己的对象。这样还是不能理解的话。我们就先来认清什么是抽象化,什么是实现化,什么是脱耦。
- 抽象化:从众多的事物中抽取出共同的、本质性的特征,而舍弃其非本质的特征,就是抽象化。例如苹果、香蕉、生梨、 桃子等,它们共同的特性就是水果。得出水果概念的过程,就是一个抽象化的过程。要抽象,就必须进行比较,没有比较就无法找到在本质上共同的部分。共同特征是指那些能把一类事物与他类事物区分开来的特征,这些具有区分作用的特征又称本质特征。因此抽取事物的共同特征就是抽取事物的本质特征,舍弃非本质的特征。 所以抽象化的过程也是一个裁剪的过程。在抽象时,同与不同,决定于从什么角度上来抽象。抽象的角度取决于分析问题的目的。通常情况下,一组对象如果具有相同的特征,那么它们就可以通过一个共同的类来描述。如果一些类具有相同的特征,往往可以通过一个共同的抽象类来描述。
- 实现化:抽象化给出的具体实现,就是实现化。一个类的实例就是这个类的实例化,一个具体子类是它的抽象超类的实例化。
- 脱耦:所谓耦合,就是两个实体的行为的某种强关联。而将它们的强关联去掉,就是耦合的解脱,或称脱耦。在这里,脱耦是指将抽象化和实现化之间的耦合解脱开,或者说是将它们之间的强关联改换成弱关联。所谓强关联,就是在编译时期已经确定的,无法在运行时期动态改变的关联;所谓弱关联,就是可以动态地确定并且可以在运行时期动态地改变的关联。显然,在Java语言中,继承关系是强关联,而聚合关系是弱关联。将两个角色之间的继承关系改为聚合关系,就是将它们之间的强关联改换成为弱关联。因此,桥梁模式中的所谓脱耦,就是指在一个软件系统的抽象化和实现化之间使用聚合关系而不是继承关系,从而使两者可以相对独立地变化。这就是桥梁模式的用意。
2.角色
- 抽象化(Abstraction)角色:抽象化给出的定义,并保存一个对实现化对象的引用。
- 修正抽象化(RefinedAbstraction)角色:扩展抽象化角色,改变和修正父类对抽象化的定义。
- 实现化(Implementor)角色:这个角色给出实现化角色的接口,但不给出具体的实现。必须指出的是,这个接口不一定和抽象化角色的接口定义相同,实际上,这两个接口可以非常不一样。实现化角色应当只给出底层操作,而抽象化角色应当只给出基于底层操作的更高一层的操作。
- 具体实现化(ConcreteImplementor)角色:这个角色给出实现化角色接口的具体实现。
3.UML类图
4.举例说明
例如:我们现在要画三种形状,分别是长方形,圆形和正方形。而且可以分别用三种颜色来画。
代码如下:
首先是形状类:该类为一个抽象类,主要提供画图形的方法
public abstract class Shape {
Color color;
public void setColor(Color color) {
this.color = color;
}
public abstract void draw();
}
然后是画三个形状的类
public class Circle extends Shape{
public void draw() {
color.bepaint("正方形");
}
}
public class Rectangle extends Shape{
public void draw() {
color.bepaint("长方形");
}
}
public class Square extends Shape{
public void draw() {
color.bepaint("正方形");
}
}
画形状所用的颜色接口
public interface Color {
public void bepaint(String shape);
}
用于画形状的三种颜色类
public class Gray implements Color{
public void bepaint(String shape) {
System.out.println("灰色的" + shape);
}
}
public class Black implements Color{
public void bepaint(String shape) {
System.out.println("黑色的" + shape);
}
}
public class White implements Color{
public void bepaint(String shape) {
System.out.println("白色的" + shape);
}
}
客户端
public class Client {
public static void main(String[] args) {
//白色
Color white = new White();
//正方形
Shape square = new Square();
//白色的正方形
square.setColor(white);
square.draw();
//长方形
Shape rectange = new Rectangle();
rectange.setColor(white);
rectange.draw();
}
}
运行结果:
白色的正方形
白色的长方形
注意:可以将shape中的setColor删去,改为添加一个构造方法,利用构造方法给Shape中的color初始化也是可以的。
5.桥接模式通用代码
/*
* 实现化角色
*/
public interface Implementor {
// 基本方法
public void doSomething();
public void doAnything();
}
/*
* 具体实现化角色
*/
public class ConcreteImplementor1 implements Implementor {
public void doAnything() {
// 业务处理逻辑
}
public void doSomething() {
// 业务处理逻辑
}
}
public class ConcreteImplementor2 implements Implementor {
public void doAnything() {
// 业务处理逻辑
}
public void doSomething() {
// 业务处理逻辑
}
}
/*
* 抽象化角色
*/
public abstract class Abstraction {
// 定义对实现化角色的引用
private Implementor imp;
// 约束子类必须实现该构造函数
public Abstraction(Implementor _imp) {
this.imp = _imp;
}
// 自身的行为和属性
public void request() {
this.imp.doSomething();
}
// 获得实现化角色
public Implementor getImp() {
return this.imp;
}
}
/*
* 具体抽象化角色
*/
public class RefinedAbstraction extends Abstraction {
// 覆写构造函数
public RefinedAbstraction(Implementor _imp) {
super(_imp);
}
// 修正父类的行为
public void request() {
super.request();
super.getImp().doAnything();
}
}
/*
* 客户端
*/
public class Client {
public static void main(String[] args) {
// 定义一个实现化角色
Implementor imp = new ConcreteImplementor1();
// 定义一个抽象化角色
Abstraction abs = new RefinedAbstraction(imp);
// 执行行文
abs.request();
}
}
6.桥接模式优点
- 实现了抽象和实现部分的分离:桥接模式分离了抽象部分和实现部分,从而极大的提供了系统的灵活性,让抽象部分和实现部分独立开来,分别定义接口,这有助于系统进行分层设计,从而产生更好的结构化系统。对于系统的高层部分,只需要知道抽象部分和实现部分的接口就可以了。
- 更好的可扩展性:由于桥接模式把抽象部分和实现部分分离了,从而分别定义接口,这就使得抽象部分和实现部分可以分别独立扩展,而不会相互影响,大大的提供了系统的可扩展性。
- 可动态的切换实现,由于桥接模式实现了抽象和实现的分离,所以在实现桥接模式时,就可以实现动态的选择和使用具体的实现。
- 实现细节对客户端透明,可以对用户隐藏实现细节。分离抽象接口及其实现部分。提高了比继承更好的解决方案。
7.桥接模式缺点
- 桥接模式的引入增加了系统的理解和设计难度,由于聚合关联关系建立在抽象层,要求开发者针对抽象进行设计和编程。
- 桥接模式要求正确识别出系统中两个独立变化的维度,因此其使用范围有一定的局限性。
8.桥接模式适用场景
- 如果一个系统需要在构件的抽象化角色和具体化角色之间增加更多的灵活性,避免在两个层次之间建立静态的继承联系,通过桥接模式可以使它们在抽象层建立一个关联关系。
- 抽象化角色和实现化角色可以以继承的方式独立扩展而互不影响,在程序运行时可以动态将一个抽象化子类的对象和一个实现化子类的对象进行组合,即系统需要对抽象化角色和实现化角色进行动态耦合。
- 一个类存在两个独立变化的维度,且这两个维度都需要进行扩展。
- 虽然在系统中使用继承是没有问题的,但是由于抽象化角色和具体化角色需要独立变化,设计要求需要独立管理这两者。
- 对于那些不希望使用继承或因为多层次继承导致系统类的个数急剧增加的系统,桥接模式尤为适用