处理多维度变化——桥接模式(三)

10.3 完整解决方案

为了减少所需生成的子类数目,实现将操作系统和图像文件格式两个维度分离,使它们可以独立改变,Sunny公司开发人员使用桥接模式来重构跨平台图像浏览系统的设计,其基本结构如图10-5所示:

处理多维度变化——桥接模式(三) - 图1

在图10-5中,Image充当抽象类,其子类JPGImage、PNGImage、BMPImage和GIFImage充当扩充抽象类;ImageImp充当实现类接口,其子类WindowsImp、LinuxImp和UnixImp充当具体实现类。完整代码如下所示:

  1. //像素矩阵类:辅助类,各种格式的文件最终都被转化为像素矩阵,不同的操作系统提供不同的方式显示像素矩阵
  2. class Matrix {
  3. //此处代码省略
  4. }
  5. //抽象图像类:抽象类
  6. abstract class Image {
  7. protected ImageImp imp;
  8. public void setImageImp(ImageImp imp) {
  9. this.imp = imp;
  10. }
  11. public abstract void parseFile(String fileName);
  12. }
  13. //抽象操作系统实现类:实现类接口
  14. interface ImageImp {
  15. public void doPaint(Matrix m); //显示像素矩阵m
  16. }
  17. //Windows操作系统实现类:具体实现类
  18. class WindowsImp implements ImageImp {
  19. public void doPaint(Matrix m) {
  20. //调用Windows系统的绘制函数绘制像素矩阵
  21. System.out.print("在Windows操作系统中显示图像:");
  22. }
  23. }
  24. //Linux操作系统实现类:具体实现类
  25. class LinuxImp implements ImageImp {
  26. public void doPaint(Matrix m) {
  27. //调用Linux系统的绘制函数绘制像素矩阵
  28. System.out.print("在Linux操作系统中显示图像:");
  29. }
  30. }
  31. //Unix操作系统实现类:具体实现类
  32. class UnixImp implements ImageImp {
  33. public void doPaint(Matrix m) {
  34. //调用Unix系统的绘制函数绘制像素矩阵
  35. System.out.print("在Unix操作系统中显示图像:");
  36. }
  37. }
  38. //JPG格式图像:扩充抽象类
  39. class JPGImage extends Image {
  40. public void parseFile(String fileName) {
  41. //模拟解析JPG文件并获得一个像素矩阵对象m;
  42. Matrix m = new Matrix();
  43. imp.doPaint(m);
  44. System.out.println(fileName + ",格式为JPG。");
  45. }
  46. }
  47. //PNG格式图像:扩充抽象类
  48. class PNGImage extends Image {
  49. public void parseFile(String fileName) {
  50. //模拟解析PNG文件并获得一个像素矩阵对象m;
  51. Matrix m = new Matrix();
  52. imp.doPaint(m);
  53. System.out.println(fileName + ",格式为PNG。");
  54. }
  55. }
  56. //BMP格式图像:扩充抽象类
  57. class BMPImage extends Image {
  58. public void parseFile(String fileName) {
  59. //模拟解析BMP文件并获得一个像素矩阵对象m;
  60. Matrix m = new Matrix();
  61. imp.doPaint(m);
  62. System.out.println(fileName + ",格式为BMP。");
  63. }
  64. }
  65. //GIF格式图像:扩充抽象类
  66. class GIFImage extends Image {
  67. public void parseFile(String fileName) {
  68. //模拟解析GIF文件并获得一个像素矩阵对象m;
  69. Matrix m = new Matrix();
  70. imp.doPaint(m);
  71. System.out.println(fileName + ",格式为GIF。");
  72. }
  73. }

为了让系统具有更好的灵活性和可扩展性,我们引入了配置文件,将具体扩充抽象类和具体实现类类名都存储在配置文件中,再通过反射生成对象,将生成的具体实现类对象注入到扩充抽象类对象中,其中,配置文件config.xml的代码如下所示:

  1. <?xml version="1.0"?>
  2. <config>
  3. <!--RefinedAbstraction-->
  4. <className>JPGImage</className>
  5. <!--ConcreteImplementor-->
  6. <className>WindowsImp</className>
  7. </config>

用于读取配置文件config.xml并反射生成对象的XMLUtil类的代码如下所示:

  1. import javax.xml.parsers.*;
  2. import org.w3c.dom.*;
  3. import org.xml.sax.SAXException;
  4. import java.io.*;
  5. public class XMLUtil {
  6. //该方法用于从XML配置文件中提取具体类类名,并返回一个实例对象
  7. public static Object getBean(String args) {
  8. try {
  9. //创建文档对象
  10. DocumentBuilderFactory dFactory = DocumentBuilderFactory.newInstance();
  11. DocumentBuilder builder = dFactory.newDocumentBuilder();
  12. Document doc;
  13. doc = builder.parse(new File("config.xml"));
  14. NodeList nl=null;
  15. Node classNode=null;
  16. String cName=null;
  17. nl = doc.getElementsByTagName("className");
  18. if(args.equals("image")) {
  19. //获取第一个包含类名的节点,即扩充抽象类
  20. classNode=nl.item(0).getFirstChild();
  21. }
  22. else if(args.equals("os")) {
  23. //获取第二个包含类名的节点,即具体实现类
  24. classNode=nl.item(1).getFirstChild();
  25. }
  26. cName=classNode.getNodeValue();
  27. //通过类名生成实例对象并将其返回
  28. Class c=Class.forName(cName);
  29. Object obj=c.newInstance();
  30. return obj;
  31. }
  32. catch(Exception e) {
  33. e.printStackTrace();
  34. return null;
  35. }
  36. }
  37. }

编写如下客户端测试代码:

  1. class Client {
  2. public static void main(String args[]) {
  3. Image image;
  4. ImageImp imp;
  5. image = (Image)XMLUtil.getBean("image");
  6. imp = (ImageImp)XMLUtil.getBean("os");
  7. image.setImageImp(imp);
  8. image.parseFile("小龙女");
  9. }
  10. }

编译并运行程序,输出结果如下:

  1. Windows操作系统中显示图像:小龙女,格式为JPG

如果需要更换图像文件格式或者更换操作系统,只需修改配置文件即可,在实际使用时,可以通过分析图像文件格式后缀名来确定具体的文件格式,在程序运行时获取操作系统信息来确定操作系统类型,无须使用配置文件。当增加新的图像文件格式或者操作系统时,原有系统无须做任何修改,只需增加一个对应的扩充抽象类或具体实现类即可,系统具有较好的可扩展性,完全符合“开闭原则”。