桥接模式(别名:柄体模式)
将抽象部分于它的实现部分分离,使它们都可以独立地变化。
Bridge Pattern(Another Name:Handle-Body)
Decouple an abstraction from its implementation so that the two can vary independently.
类图
模式的结构与使用
桥接模式的结构中包括四种角色。
+ 抽象(Abstraction):是一个抽象类,该抽象类含有Implementor声明的变量,即维护一个Implementor类型对象。
+ 实现者(Implementor):实现者角色是一个接口(抽象类),该接口(抽象类)中的方法不一定与Abstraction类中的方法一致。Implementor接口(抽象类)负责定义基本操作,而Abstraction类负责定义基于这些基本操作的较高层次的操作。
+ 细化抽象(Refined Abstration):细化抽象是抽象角色的一个子类,该子类在重写(覆盖)抽象角色中的抽象方法时,在给出一些必要的操作后,将委托所维护Implementor类型对象调用相应的方法。
+ 具体实现者(Concrete Implementor):具体实现者是实现(扩展)Implementor接口(抽象类)的类。
简单的例子
Abstract Template的抽象类CCTV.java
package Bridge;
import javax.swing.JPanel;
public abstract class CCTV extends JPanel {
Program programMaker;
public abstract void makeProgram();
}
Abstract Template的实现类CCTV5.java
package Bridge;
import java.awt.BorderLayout;
import java.awt.Font;
import java.util.ArrayList;
import javax.swing.JLabel;
public class CCTV5 extends CCTV implements Runnable {
JLabel showFilm;
Thread thread;
ArrayList<String> content;
public CCTV5(Program program) {
programMaker = program;
setLayout(new BorderLayout());
showFilm = new JLabel("CCTV5频道");
showFilm.setFont(new Font("", Font.BOLD, 39));
add(showFilm, BorderLayout.CENTER);
thread = new Thread(this);
}
@Override
public void makeProgram() {
content = programMaker.makeTVProgram();
if (!thread.isAlive()) {
thread = new Thread(this);
thread.start();
}
}
@Override
public void run() {
for (int i = 0; i < content.size(); i++) {
showFilm.setText(content.get(i));
try {
Thread.sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
Abstract Template的实现类CCTV6.java
package Bridge;
import java.awt.BorderLayout;
import java.awt.Font;
import java.util.ArrayList;
import javax.swing.JLabel;
public class CCTV6 extends CCTV implements Runnable {
JLabel showFilm;
Thread thread;
ArrayList<String> content;
public CCTV6(Program program) {
programMaker = program;
setLayout(new BorderLayout());
showFilm = new JLabel("CCTV6频道");
showFilm.setFont(new Font("", Font.BOLD, 39));
add(showFilm, BorderLayout.CENTER);
thread = new Thread(this);
}
@Override
public void makeProgram() {
content = programMaker.makeTVProgram();
if (!thread.isAlive()) {
thread = new Thread(this);
thread.start();
}
}
@Override
public void run() {
for (int i = 0; i < content.size(); i++) {
showFilm.setText(content.get(i));
try {
Thread.sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
Implementor的接口类Program.java
package Bridge;
import java.util.ArrayList;
public interface Program {
public ArrayList<String> makeTVProgram();
}
Implementor的实现类AthleticProgram.java
package Bridge;
import java.util.ArrayList;
public class AthleticProgram implements Program {
ArrayList<String> content;
public AthleticProgram() {
content = new ArrayList<String>();
}
@Override
public ArrayList<String> makeTVProgram() {
content.clear();
content.add("足球直播");
content.add("篮球直播");
content.add("羽毛球直播");
content.add("兵乓球直播");
content.add("直播结束");
return content;
}
}
Implementor的实现类FilmProgram.java
package Bridge;
import java.util.ArrayList;
public class FilmProgram implements Program {
ArrayList<String> content;
public FilmProgram() {
content = new ArrayList<String>();
}
@Override
public ArrayList<String> makeTVProgram() {
content.clear();
content.add("惊天魔盗团");
content.add("兵临城下");
content.add("海芋恋");
content.add("寒战");
content.add("电影结束");
return content;
}
}
测试类Application.java
package Bridge;
import java.awt.BorderLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JButton;
import javax.swing.JFrame;
public class Application extends JFrame {
JButton seeProgram;
CCTV cctv;
Program program;
public Application(CCTV tv, Program program) {
this.cctv = tv;
this.program = program;
add(cctv, BorderLayout.CENTER);
seeProgram = new JButton("看节目");
add(seeProgram, BorderLayout.SOUTH);
seeProgram.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
cctv.makeProgram();
}
});
setVisible(true);
setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
}
public static void main(String[] args) {
Program program = new AthleticProgram();
CCTV cctv = new CCTV5(program);
Application application1 = new Application(cctv, program);
application1.setBounds(10, 10, 200, 300);
program = new FilmProgram();
cctv = new CCTV6(program);
Application application2 = new Application(cctv, program);
application2.setBounds(220, 10, 200, 300);
}
}
运行截图
桥接模式的优点
- 桥接模式分离实现与抽象,使抽象和实现可以独立的扩展。当修改实现的代码时,不影响抽象的代码,反之也一样。
- 满足开闭-原则。抽象和实现者处于同层次,使系统可独立地扩展这两个层次。增加新的具体实现者,不需要修改细化抽象,反之增加新的细化抽象也不需要修改具体实现。
适用桥接模式的情景
- 不想让抽象和某些重要的实现代码是固定的绑定关系,这部分实现可运行时动态决定。
- 抽象和实现者都可以继承的方式独立地扩充而互不影响,程序在运行期间可能需要动态的将一个抽象的子类的实例与一个实现者的子类的实例进行结合。
- 希望对实现者层次代码的修改对抽象层不产生影响,即抽象层的代码不必重新编译,反之亦然。