桥接模式(Bridge),将抽象部分和它的实现部分分离,使它们都可以独立地变化。
桥接模式基于类的最小设计原则,通过使用封装、聚合及继承等行为让不同的类承担不同的职责。它的主要特点是把抽象与行为实现分离开来,从而可以保持各部分的独立性以及应对它们的功能扩展。
也就是说,实现系统可能有多种方式分类,每一种分类都有可能变化。桥接模式的核心意图就是把这些分类独立出来,让它们各自独立变化,减少它们之间的耦合。
桥接模式解析
![桥接模式结构图]()
角色介绍
- Abstraction:维护了 Implementor 类,两者是聚合关系,Abstraction 充当桥接类。
- RefinedAbstraction:是 Abstraction 抽象类的子类。
- Implementor:行为实现类的接口。
- ConcreteImplementorA/ConcreteImplementorA:行为的具体实现类。
桥接模式基本代码
1 | public abstract class Abstraction { |
2 |
|
3 | private Implementor implementor; |
4 |
|
5 | public Abstraction(Implementor implementor) { |
6 | this.implementor = implementor; |
7 | } |
8 |
|
9 | protected void operation() { |
10 | implementor.operation(); |
11 | } |
12 | } |
1 | public class RefinedAbstraction extends Abstraction { |
2 |
|
3 | public RefinedAbstraction(Implementor implementor) { |
4 | super(implementor); |
5 | } |
6 |
|
7 | @Override |
8 | protected void operation() { |
9 | super.operation(); |
10 | } |
11 | } |
1 | public interface Implementor { |
2 |
|
3 | void operation(); |
4 | } |
1 | public class ConcreteImplementorA implements Implementor { |
2 |
|
3 | @Override |
4 | public void operation() { |
5 | System.out.println("具体实现 A 的方法执行"); |
6 | } |
7 | } |
1 | public class ConcreteImplementorB implements Implementor { |
2 |
|
3 | @Override |
4 | public void operation() { |
5 | System.out.println("具体实现 B 的方法执行"); |
6 | } |
7 | } |
1 | public class Main { |
2 |
|
3 | public static void main(String[] args) { |
4 | Implementor implementorA = new ConcreteImplementorA(); |
5 | Abstraction refinedAbstractionA = new RefinedAbstraction(implementorA); |
6 | refinedAbstractionA.operation(); |
7 |
|
8 | Implementor implementorB = new ConcreteImplementorB(); |
9 | Abstraction refinedAbstractionB = new RefinedAbstraction(implementorB); |
10 | refinedAbstractionB.operation(); |
11 | } |
12 | } |
示例
手机操作问题,对不同品牌手机的不同软件功能进行编程,如通讯录、手机游戏等。
传统方法
![代码结构图]()
1 |
|
2 |
|
3 |
|
4 | public abstract class AbstractHandset { |
5 |
|
6 | public abstract void run(); |
7 | } |
1 |
|
2 |
|
3 |
|
4 | public abstract class HandsetM extends AbstractHandset { |
5 |
|
6 |
|
7 | } |
8 |
|
9 |
|
10 |
|
11 |
|
12 | public abstract class HandsetN extends AbstractHandset { |
13 | |
14 | } |
1 |
|
2 |
|
3 |
|
4 | public class HandsetMGame extends HandsetM { |
5 |
|
6 | @Override |
7 | public void run() { |
8 | System.out.println("运行 M 品牌手机的游戏"); |
9 | } |
10 | } |
11 |
|
12 |
|
13 |
|
14 |
|
15 | public class HandsetNGame extends HandsetN { |
16 |
|
17 | @Override |
18 | public void run() { |
19 | System.out.println("运行 N 品牌手机的游戏"); |
20 | } |
21 | } |
22 |
|
23 |
|
24 |
|
25 |
|
26 | public class HandsetMMP3 extends HandsetM { |
27 |
|
28 | @Override |
29 | public void run() { |
30 | System.out.println("运行 M 品牌手机的 MP3"); |
31 | } |
32 | } |
33 |
|
34 |
|
35 |
|
36 |
|
37 | public class HandsetNMP3 extends HandsetN { |
38 |
|
39 | @Override |
40 | public void run() { |
41 | System.out.println("运行 N 品牌手机的 MP3"); |
42 | } |
43 | } |
1 |
|
2 |
|
3 |
|
4 | public class Main { |
5 |
|
6 | public static void main(String[] args) { |
7 | HandsetM handsetM = new HandsetMGame(); |
8 | handsetM.run(); |
9 |
|
10 | HandsetN handsetN = new HandsetNMP3(); |
11 | handsetN.run(); |
12 | } |
13 | } |
传统方法使用多层继承的方案,在扩展上存在类爆炸的问题。当我们要给每个品牌的手机增加一个新功能时,就要在每个品牌的手机下面增加一个子类,这样增加了代码维护的成本。
事实上,很多情况下使用继承会带来麻烦。对象的继承关系是在编译时就定义好了的,所以无法在运行时改变从父类继承的实现。子类的实现与它的父类有非常紧密的依赖关系,以至于父类实现中的任何变化必然导致其子类发生变化。当需要复用子类时,如果继承下来的实现不适合解决新的问题,则父类必须重写或被其他更适合的类替换。这种依赖关系限制了灵活性并最终限制复用。
使用桥接模式改进
![桥接结构图]()
1 |
|
2 |
|
3 |
|
4 | public interface HandsetSoft { |
5 |
|
6 | void run(); |
7 | } |
1 |
|
2 |
|
3 |
|
4 | public class HandsetGame implements HandsetSoft { |
5 |
|
6 | @Override |
7 | public void run() { |
8 | System.out.println("运行手机游戏"); |
9 | } |
10 | } |
11 |
|
12 |
|
13 |
|
14 |
|
15 | public class HandsetMP3 implements HandsetSoft { |
16 |
|
17 | @Override |
18 | public void run() { |
19 | System.out.println("运行手机 MP3"); |
20 | } |
21 | } |
1 |
|
2 |
|
3 |
|
4 | public abstract class AbstractHandset { |
5 |
|
6 | protected HandsetSoft handsetSoft; |
7 |
|
8 | public AbstractHandset(HandsetSoft handsetSoft) { |
9 | this.handsetSoft = handsetSoft; |
10 | } |
11 |
|
12 | public abstract void run(); |
13 | } |
1 |
|
2 |
|
3 |
|
4 | public class HandsetM extends AbstractHandset { |
5 |
|
6 | public HandsetM(HandsetSoft handsetSoft) { |
7 | super(handsetSoft); |
8 | } |
9 |
|
10 | @Override |
11 | public void run() { |
12 | this.handsetSoft.run(); |
13 | } |
14 | } |
15 |
|
16 |
|
17 |
|
18 |
|
19 | public class HandsetN extends AbstractHandset { |
20 |
|
21 | public HandsetN(HandsetSoft handsetSoft) { |
22 | super(handsetSoft); |
23 | } |
24 |
|
25 | @Override |
26 | public void run() { |
27 | this.handsetSoft.run(); |
28 | } |
29 | } |
1 |
|
2 |
|
3 |
|
4 | public class Main { |
5 |
|
6 | public static void main(String[] args) { |
7 | HandsetM handsetM = new HandsetM(new HandsetGame()); |
8 | handsetM.run(); |
9 |
|
10 | HandsetN handsetN = new HandsetN(new HandsetMP3()); |
11 | handsetN.run(); |
12 | } |
13 | } |
小结
桥接模式,实现了抽象和实现部分的分离,从而极大的提供了系统的灵活性,让抽象部分和实现部分独立开来,这有助于系统进行分层设计,从而产生更好的结构化系统。对于系统的高层部分,只需要知道抽象部分和实现部分的接口就可以了,其它的部分由具体业务来完成。桥接模式替代多层继承方案,可以减少子类的个数,降低系统的管理和维护成本。
桥接模式要求正确识别出系统中两个独立变化的维度(抽象和实现),因此其使用范围有一定的局限性,即需要有这样的应用场景。