设计模式-桥接模式的应用
桥接模式的应用
某软件公司要开发一个跨平台图像浏览系统,要求该系统能够显示BMP、JPG、GIF、PNG等多种格式的文件,并且能够在Windows、Linux、UNIX等多个操作系统上运行。系统首先将各种格式的文件解析为像素矩阵(Matrix),然后将像素矩阵显示在屏幕上,在不同的操作系统中可以调用不同的绘制函数来绘制像素矩阵。另外,系统需具有较好的扩展性,以便在将来支持新的文件格式和操作系统。
现使用桥接模式设计该跨平台图像浏览系统。
用JAVA语言实现该模式。绘制该模式的UML图。
【模式UML图】
【模式代码】
// Matrix.java:
package sdp.sy_8.bridgepattern;
//像素矩阵类:辅助类,各种格式的文件都被转化为像素矩阵,不同的操作系统提供不同的方式
//显示像素矩阵
public class Matrix {
//此处代码省略
}
// Image.java:
package sdp.sy_8.bridgepattern;
//抽象图像类
public abstract class Image {
protected ImageImp imageImp;
public void setImageImp(ImageImp imageImp) {
this.imageImp = imageImp;
}
public abstract void parseFile(String fileName);
}
// ImageImp.java:
package sdp.sy_8.bridgepattern;
//抽象操作系统实现类:实现类接口
public interface ImageImp {
public void doPaint(Matrix matrix); //显示像素矩阵
}
// WindowsImp.java:
package sdp.sy_8.bridgepattern;
//Windows操作系统实现类:实现类接口
public class WindowsImp implements ImageImp {
@Override
public void doPaint(Matrix matrix) {
//调用Windows系统的绘制函数绘制像素矩阵
System.out.println("在Windows操作系统中显示图像:");
}
}
// LinuxImp.java:
package sdp.sy_8.bridgepattern;
//Linux操作系统实现类:实现类接口
public class LinuxImp implements ImageImp {
@Override
public void doPaint(Matrix matrix) {
// 调用Linux系统的绘制函数绘制像素矩阵
System.out.println("在Linux操作系统中显示图像:");
}
}
// UnixImp.java:
package sdp.sy_8.bridgepattern;
//Unix操作系统实现类:实现类接口
public class UnixImp implements ImageImp {
@Override
public void doPaint(Matrix matrix) {
// 调用Unix系统的绘制函数绘制像素矩阵
System.out.println("在Unix操作系统中显示图像:");
}
}
// JPGImage.java:
package sdp.sy_8.bridgepattern;
//JPG格式图像:扩充抽象类
public class JPGImage extends Image{
@Override
public void parseFile(String fileName) {
// 模拟解析JPG文件并获得一个像素矩阵对象matrix
Matrix matrix = new Matrix();
imageImp.doPaint(matrix);
System.out.println(fileName+",格式为JPG");
}
}
// PNGImage.java:
package sdp.sy_8.bridgepattern;
//PNG格式图像:扩充抽象类
public class PNGImage extends Image{
@Override
public void parseFile(String fileName) {
// // 模拟解析PNG文件并获得一个像素矩阵对象matrix
Matrix matrix = new Matrix();
imageImp.doPaint(matrix);
System.out.println(fileName+",格式为PNG.");
}
}
// BMPImage.java:
package sdp.sy_8.bridgepattern;
//BMP格式图像:扩充抽象类
public class BMPImage extends Image{
@Override
public void parseFile(String fileName) {
// // 模拟解析BMP文件并获得一个像素矩阵对象matrix
Matrix matrix = new Matrix();
imageImp.doPaint(matrix);
System.out.println(fileName+",格式为BMP");
}
}
// GIFImage.java:
package sdp.sy_8.bridgepattern;
//GIF格式图像:扩充抽象类
public class GIFImage extends Image{
@Override
public void parseFile(String fileName) {
// 模拟解析GIF文件并获得一个像素矩阵对象matrix
Matrix matrix = new Matrix();
imageImp.doPaint(matrix);
System.out.println(fileName+",格式为GIF.");
}
}
<?xml version="1.0" encoding="UTF-8"?>
<config>
<!-- RefinedAbstraction -->
<className>sdp.sy_8.bridgepattern.PNGImage</className>
<!-- ConcreteImplementor -->
<className>sdp.sy_8.bridgepattern.WindowsImp</className>
</config>
// XMLUtil.java:
package sdp.sy_8.bridgepattern;
import javax.xml.parsers.*;
import org.w3c.dom.*;
import java.io.*;
import org.w3c.dom.NodeList;
public class XMLUtil {
//该方法用于从XML配置文件中提取具体的类类名,并返回一个实例对象
public static Object getBean(String args) {
try {
//创建文档对象
DocumentBuilderFactory dFactory = DocumentBuilderFactory.newInstance();
DocumentBuilder builder = dFactory.newDocumentBuilder();
Document doc;
doc = builder.parse(new File("config.xml"));
NodeList nl = null;
Node classNode = null;
String cName = null;
nl = doc.getElementsByTagName("className");
if(args.equals("image")) {
//获取第一个包含类名的节点,即扩充抽象类
classNode = nl.item(0).getFirstChild();
}
else if (args.equals("os")) {
//获取第二个包含类名的节点,即具体实现类
classNode = nl.item(1).getFirstChild();
}
cName = classNode.getNodeValue();
//通过类名生成实例对象并将其返回
Class c = Class.forName(cName);
Object obj = c.newInstance();
return obj;
} catch(Exception e) {
e.printStackTrace();
return null;
}
}
}
【运行截图】
桥接模式主要适用于以下情况:
- 如果一个系统需要在抽象类和具体类之间增加更多的灵活性,避免在两个层次之间建立静态的继承关系,通过桥接模式可以使它们在抽象层建立一个关联关系。
- 抽象部分和实现部分可以以继承的方式独立扩展而互不影响,在程序运行时可以动态的将一个抽象类子类的对象和一个实现类子类的对象进行组合,及系统需要对抽象类角色和实现类角色进行动态耦合。
- 一个类存在两个(或多个)独立变化的维度,且这两个(或多个)维度都需要独立进行扩展。
- 对于那些不希望使用继承或因为多层继承导致系统的个数急剧增加的系统,桥接模式尤为适用。
顺便说一下:我这里使用eclipse进行编码和运行的,config.xml文件是建在当前工程的目录下的,即eclipse的工程中的src的同一级目录,还有,我的每一个java文件都是建在包下面的,所以config.xml中需要输入包名,XMLUtil.java文件才能正确获取到文件进行解析。主要是需要注意一下config.xml文件新建的位置以及内容需要带上包名。