桥接模式
1.桥接模式是什么
1.百度百科
桥接模式(Bridge pattern)是将抽象部分与它的实现部分分离,使它们都可以独立地变化。它是一种对象结构型模式,又称为柄体(Handle and Body)模式或接口(Interface)模式。
话说百度百科越来越不靠谱了
2.维基百科
The bridge pattern is a design pattern used in software engineering that is meant to "decouple an abstraction from its implementation so that the two can vary independently", introduced by the Gang of Four.[1] The bridge uses encapsulation, aggregation, and can use inheritance to separate responsibilities into different classes.
When a class varies often, the features of object-oriented programming become very useful because changes to a program's code can be made easily with minimal prior knowledge about the program. The bridge pattern is useful when both the class and what it does vary often. The class itself can be thought of as the abstraction and what the class can do as the implementation. The bridge pattern can also be thought of as two layers of abstraction.
When there is only one fixed implementation, this pattern is known as the Pimpl idiom in the C++ world.
The bridge pattern is often confused with the adapter pattern. In fact, the bridge pattern is often implemented using the object adapter pattern, e.g. in the Java code below.
Variant: The implementation can be decoupled even more by deferring the presence of the implementation to the point where the abstraction is utilized.**
3.lz理解
将现实化的对象用抽象化的中间层隔开。现实对象依赖接口,中间层也依赖接口。
以便于增加接口实现类而不影响项目整体架构。简单来说就是用抽象类和接口将各个接口的实现类隔离开从而达到一种实现类和另外一种接口的实现类解除耦合而让其各自变化的目的。
4.核心角色
抽象化(Abstraction)角色:抽象化给出的定义,并保存一个对实现化对象的引用。
修正抽象化(Refined Abstraction)角色:扩展抽象化角色,改变和修正父类对抽象化的定义。
抽象实现化(Implementor)角色:这个角色给出实现化角色的接口,但不给出具体的实现。必须指出的是,这个接口不一定和抽象化角色的接口定义相同,实际上,这两个接口可以非常不一样。实现化角色应当只给出底层操作,而抽象化角色应当只给出基于底层操作的更高一层的操作。
具体实现化(Concrete Implementor)角色:这个角色给出实现化角色接口的具体实现。
2.桥接模式解决了什么问题
抽象实现分离 分离抽象接口及其实现部分。提高了比继承更好的解决方案。
降低实现更换难度 桥接模式提高了系统的可扩充性,在任意一个接口中任意扩展一个实现类,都不需要修改原有系统。
隐藏实现方式 实现细节对客户透明,可以对用户隐藏实现细节。
3.桥接模式用法
就拿乘坐铁路来举例子,铁路一定有一个目的地和一个出发地。而这两个地方是不断变换的。下面我就演示怎么动态切换起始地目地的方法。
首先是起始地、目的地的抽象角色就是上文中抽象现实化角色。
//起始站抽象
public interface Startinglace {
public void fromWhere();
}
//终点站抽象
public interface Endinglace {
public void toWhere();
}
具体实现化角色
//具体出发地
public class StartinglaceBeijing implements Startinglace {
@Override
public void fromWhere() {
System.out.println("从北京出发");
}
}
public class StartinglaceGuangzhou implements Startinglace {
@Override
public void fromWhere() {
System.out.println("从广州出发");
}
}
public class StartinglaceShanghai implements Startinglace {
@Override
public void fromWhere() {
System.out.println("从上海出发");
}
}
//具体目的地
public class EndinglaceBeijin implements Endinglace {
@Override
public void toWhere() {
System.out.println("到达北京");
}
}
public class EndinglaceGuangzhou implements Endinglace {
@Override
public void toWhere() {
System.out.println("到达广州");
}
}
public class EndinglaceShanghai implements Endinglace {
@Override
public void toWhere() {
System.out.println("到达上海");
}
}
火车站发车、抽象化角色
/**
* 铁路
*/
public abstract class Railway {
//来源地
private Startinglace startinglace;
//目的地
private Endinglace endinglace;
public Railway(Startinglace startinglace, Endinglace endinglace) {
super();
this.startinglace = startinglace;
this.endinglace = endinglace;
}
//铁路具体运行方式
public abstract void run();
public Startinglace getStartinglace() {
return startinglace;
}
public void setStartinglace(Startinglace startinglace) {
this.startinglace = startinglace;
}
public Endinglace getEndinglace() {
return endinglace;
}
public void setEndinglace(Endinglace endinglace) {
this.endinglace = endinglace;
}
}
具体铁路的运行、修正抽象化角色
public class RailwayRuning extends Railway {
public RailwayRuning(Startinglace startinglace, Endinglace endinglace) {
super(startinglace, endinglace);
}
@Override
public void run() {
super.getStartinglace().fromWhere();;
super.getEndinglace().toWhere();;
}
}
客户端的调用
public class Customer {
public static void main(String[] args) {
//从广州到北京
StartinglaceGuangzhou startinglaceGuangzhou = new StartinglaceGuangzhou();
EndinglaceBeijin endinglaceBeijin = new EndinglaceBeijin();
RailwayRuning railwayRuning = new RailwayRuning(startinglaceGuangzhou,endinglaceBeijin);
railwayRuning.run();
//从上海到广州
StartinglaceShanghai startinglaceShanghai = new StartinglaceShanghai();
EndinglaceGuangzhou endinglaceGuangzhou = new EndinglaceGuangzhou();
railwayRuning = new RailwayRuning(startinglaceShanghai,endinglaceGuangzhou);
//railwayRuning.run();
//突然有急事要去北京
railwayRuning.setEndinglace(endinglaceBeijin);
railwayRuning.run();
}
}
从上述例子中可以看出始发站和目的地都是可以随意拓展的只需继承各自的抽象化角色。目的地切换也非常容易,目的地和出发地完全依赖抽象化的角色。将实现用抽象类隔开从而达到解除耦合的目的。
4.桥接模式的问题
系统复杂度增加 桥接模式的引入会增加系统的理解与设计难度,由于聚合关联关系建立在抽象层,要求开发者针对抽象进行设计与编程。
定位独立维度困难 桥接模式要求正确识别出系统中两个独立变化的维度,因此其使用范围具有一定的局限性。
5.桥接模式总结
使用场景:
-
如果一个系统需要在构件的抽象化角色和具体化角色之间增加更多的灵活性,避免在两个层次之间建立静态的继承联系,通过桥接模式可以使它们在抽象层建立一个关联关系。
-
对于那些不希望使用继承或因为多层次继承导致系统类的个数急剧增加的系统,桥接模式尤为适用。
-
一个类存在两个独立变化的维度,且这两个维度都需要进行扩展。
设计模式缺点是增加系统的复杂性并让系统难以理解。反反复复提示自己就是应为设计模式的滥用是一个非常可怕的事情,桥接模式的使用场景的中说了通过桥接模式在抽象层建立关联关系。那么这个关联关系最好就是稳定的,如果这个关联关系并不稳定那么不适合使用桥接模式,而变化在实现的修改和拓展上。就像上面火车的例子从出发地到目的地这个结构是非常稳定的。那么变化的仅仅是出发地和目的地的实现类不同。那么动态切换出发目的地或者增加目的地都是很灵活的。