Bridge模式的作用是将两样东西连接起来,它们分别是类的功能层次结构与类的实现层次结构。该模式在类的功能层次结构与类的实现层次结构之间搭建桥梁。
类的层次结构的两个作用
1.类的功能层次结构
当要增加新的功能时,我们可以从各个层次的类中找出最符合自己需求的类,然后以它为父类编写子类,并在子类中增加新的功能。这就是“类的功能层次结构”。
通常来说,类的层次结构关系不应当关系过深。
2.类的实现层次结构
希望增加新的实现时,父类通过声明抽象方法来定义接口(API),子类通过实现具体方法来实现接口(API),这种层次结构被称为“类的实现层次结构”。
示例程序:显示一些东西
类的功能层次结构:Display类
Display类的功能是抽象的,负责显示一些东西,该类位于“类的功能层次结构”的最上层。
在impl字段中保存的是实现了Display类的具体功能的实例,该实例通过Display类的构造函数传递给Display类,然后保存在impl字段中,以供后面的处理使用。
package Bridge;
//类的功能层次上层
public class Display {
//连接功能层次结构和实现层次结构的桥梁,使用委托这种弱联系的方式
private DisplayImpl impl;
public Display(DisplayImpl impl) {
// TODO Auto-generated constructor stub
this.impl = impl;
}
//利用实现层次类的实例调用其中的方法
public void open(){
impl.rawOpen();
}
public void print(){
impl.rawPrint();
}
public void close(){
impl.rawClose();
}
public void display(){
open();
print();
close();
}
}
类的功能层次结构:CountDisplay类
CountDisplay类在Display类的基础上增加了一个新功能。Display类只有“显示”的功能,CountDisplay类则具有“只显示规定的次数”的功能。
package Bridge;
//继承父类,在子类中添加新的功能
public class CountDisplay extends Display {
public CountDisplay(DisplayImpl impl) {
// TODO Auto-generated constructor stub
super(impl);
}
public void multiDisplay(int times){
open();
for(int i=0;i<times;i++){
print();
}
close();
}
}
类的实现层次结构:DisplayImpl类
DisplayImpl类位于“类的实现层次结构”的最上层。
DisplayImpl类是抽象类,他声明了三个抽象方法。
package Bridge;
//类的实现层次接口类
public abstract class DisplayImpl {
public abstract void rawOpen();
public abstract void rawPrint();
public abstract void rawClose();
}
类的实现层次结构:StringDisplayImpl类
package Bridge;
//继承类的实现层次类,实现接口中的抽线方法
public class StringDisplayImpl extends DisplayImpl {
private String string;
private int width;
public StringDisplayImpl(String string) {
// TODO Auto-generated constructor stub
this.string = string;
width = string.getBytes().length;
}
@Override
public void rawOpen() {
// TODO Auto-generated method stub
printLine();
}
@Override
public void rawPrint() {
// TODO Auto-generated method stub
System.out.println("|"+string+"|");
}
@Override
public void rawClose() {
// TODO Auto-generated method stub
printLine();
}
private void printLine() {
// TODO Auto-generated method stub
System.out.print("+");
for(int i=0;i<width;i++){
System.out.print("-");
}
System.out.println("+");
}
}
DisplayImpl和StringDisplayImpl这两个类相当于“类的实现层次结构”。
Main类:
package Bridge;
public class Main {
public static void main(String[] args) {
// TODO Auto-generated method stub
//父类实例可以调用功能和接口
//功能子类可以调用功能和接口
Display d1 = new Display(new StringDisplayImpl("Hello world"));
Display d2 = new CountDisplay(new StringDisplayImpl("Hello china"));
CountDisplay d3 = new CountDisplay(new StringDisplayImpl("hello guys"));
d1.display();
d2.display();
d3.multiDisplay(3);
}
}
总结:将类的这两个层次结构离开有利于独立地对它们进行扩展,虽然使用继承很容易扩展类,但是类之间也形成了一种强关联关系,只要不修改代码,就无法改变这种关系。
如果想要很轻松地改变类之间的关系,使用继承就不合适了,因为每次改变类之间关系时都需要修改程序,这时,我们可以使用“委托”来代替“继承”关系。
继承是强关联关系,但委托是弱关联关系,这时因为只有Display类的实例生成时,才与作为参数被传入的类构成关联。
练习1:
在示例程序中增加一个类,实现“显示字符串若干(随机)次”的功能。
package Bridge;
import java.util.Random;
public class RandomDisplay extends CountDisplay {
private Random random = new Random();
public RandomDisplay(DisplayImpl impl) {
// TODO Auto-generated constructor stub
super(impl);
}
public void randomDisplay(int times){
multiDisplay(random.nextInt(times));
}
}
练习2:
在示例程序中增加一个类,实现“显示文本文件的内容”的功能。
package Bridge;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.io.IOException;
public class FileDisplay extends DisplayImpl {
private String filename;
private BufferedReader reader;
private final int MAX_READHEAD_LIMIT = 4096;
public FileDisplay(String filename) {
// TODO Auto-generated constructor stub
this.filename = filename;
}
@Override
public void rawOpen() {
// TODO Auto-generated method stub
try {
reader = new BufferedReader(new FileReader(filename));
reader.mark(MAX_READHEAD_LIMIT);
} catch (IOException e) {
// TODO: handle exception
e.printStackTrace();
}
System.out.println("==========="+filename+"============");
}
@Override
public void rawPrint() {
// TODO Auto-generated method stub
try {
String line;
reader.reset();
while ((line = reader.readLine()) != null){
System.out.println(">"+line);
}
} catch (IOException e) {
// TODO: handle exception
e.printStackTrace();
}
}
@Override
public void rawClose() {
// TODO Auto-generated method stub
System.out.println("==============");
try {
reader.close();
} catch (IOException e) {
// TODO: handle exception
e.printStackTrace();
}
}
}