10.3 完整解决方案
为了减少所需生成的子类数目,实现将操作系统和图像文件格式两个维度分离,使它们可以独立改变,Sunny公司开发人员使用桥接模式来重构跨平台图像浏览系统的设计,其基本结构如图10-5所示:
在图10-5中,Image充当抽象类,其子类JPGImage、PNGImage、BMPImage和GIFImage充当扩充抽象类;ImageImp充当实现类接口,其子类WindowsImp、LinuxImp和UnixImp充当具体实现类。完整代码如下所示:
//像素矩阵类:辅助类,各种格式的文件最终都被转化为像素矩阵,不同的操作系统提供不同的方式显示像素矩阵 class Matrix { //此处代码省略 } //抽象图像类:抽象类 abstract class Image { protected ImageImp imp; public void setImageImp(ImageImp imp) { this.imp = imp; } public abstract void parseFile(String fileName); } //抽象操作系统实现类:实现类接口 interface ImageImp { public void doPaint(Matrix m); //显示像素矩阵m } //Windows操作系统实现类:具体实现类 class WindowsImp implements ImageImp { public void doPaint(Matrix m) { //调用Windows系统的绘制函数绘制像素矩阵 System.out.print("在Windows操作系统中显示图像:"); } } //Linux操作系统实现类:具体实现类 class LinuxImp implements ImageImp { public void doPaint(Matrix m) { //调用Linux系统的绘制函数绘制像素矩阵 System.out.print("在Linux操作系统中显示图像:"); } } //Unix操作系统实现类:具体实现类 class UnixImp implements ImageImp { public void doPaint(Matrix m) { //调用Unix系统的绘制函数绘制像素矩阵 System.out.print("在Unix操作系统中显示图像:"); } } //JPG格式图像:扩充抽象类 class JPGImage extends Image { public void parseFile(String fileName) { //模拟解析JPG文件并获得一个像素矩阵对象m; Matrix m = new Matrix(); imp.doPaint(m); System.out.println(fileName + ",格式为JPG。"); } } //PNG格式图像:扩充抽象类 class PNGImage extends Image { public void parseFile(String fileName) { //模拟解析PNG文件并获得一个像素矩阵对象m; Matrix m = new Matrix(); imp.doPaint(m); System.out.println(fileName + ",格式为PNG。"); } } //BMP格式图像:扩充抽象类 class BMPImage extends Image { public void parseFile(String fileName) { //模拟解析BMP文件并获得一个像素矩阵对象m; Matrix m = new Matrix(); imp.doPaint(m); System.out.println(fileName + ",格式为BMP。"); } } //GIF格式图像:扩充抽象类 class GIFImage extends Image { public void parseFile(String fileName) { //模拟解析GIF文件并获得一个像素矩阵对象m; Matrix m = new Matrix(); imp.doPaint(m); System.out.println(fileName + ",格式为GIF。"); } }
为了让系统具有更好的灵活性和可扩展性,我们引入了配置文件,将具体扩充抽象类和具体实现类类名都存储在配置文件中,再通过反射生成对象,将生成的具体实现类对象注入到扩充抽象类对象中,其中,配置文件config.xml的代码如下所示:
<?xml version="1.0"?> <config> <!--RefinedAbstraction--> <className>JPGImage</className> <!--ConcreteImplementor--> <className>WindowsImp</className> </config>
用于读取配置文件config.xml并反射生成对象的XMLUtil类的代码如下所示:
import javax.xml.parsers.*; import org.w3c.dom.*; import org.xml.sax.SAXException; import java.io.*; 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; } } }
编写如下客户端测试代码:
class Client { public static void main(String args[]) { Image image; ImageImp imp; image = (Image)XMLUtil.getBean("image"); imp = (ImageImp)XMLUtil.getBean("os"); image.setImageImp(imp); image.parseFile("小龙女"); } }
编译并运行程序,输出结果如下:
在Windows操作系统中显示图像:小龙女,格式为JPG。
如果需要更换图像文件格式或者更换操作系统,只需修改配置文件即可,在实际使用时,可以通过分析图像文件格式后缀名来确定具体的文件格式,在程序运行时获取操作系统信息来确定操作系统类型,无须使用配置文件。当增加新的图像文件格式或者操作系统时,原有系统无须做任何修改,只需增加一个对应的扩充抽象类或具体实现类即可,系统具有较好的可扩展性,完全符合“开闭原则”。
Copyright© 2013-2020
All Rights Reserved 京ICP备2023019179号-8