Java设计模式之代理模式篇(2) 例3 ImageIcon对象和ImageIcon代理
import java.awt.*; import java.awt.event.*; import javax.swing.*; public class ProxyTest extends JFrame { private static String IMAGE_NAME = "hands.jpg"; private static int IMAGE_WIDTH = 430, IMAGE_HEIGHT = 390, SPACING = 5, FRAME_X = 150, FRAME_Y = 200, FRAME_WIDTH = 880, FRAME_HEIGHT = 394; private Icon imageIcon = null, imageIconProxy = null; static public void main(String args[]) { ProxyTest app = new ProxyTest(); app.show(); } public ProxyTest() { super("ImageIcon代理测试"); // 生成ImageIcon和ImageIcon代理的实例 imageIcon = new ImageIcon(IMAGE_NAME); imageIconProxy = new ImageIconProxy(IMAGE_NAME, IMAGE_WIDTH, IMAGE_HEIGHT); // 设定边框和缺省的退出操作 setBounds(FRAME_X, FRAME_Y, FRAME_WIDTH, FRAME_HEIGHT); setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); } public void paint(Graphics g) { super.paint(g); Insets insets = getInsets(); imageIcon.paintIcon(this, g, insets.left, insets.top); imageIconProxy.paintIcon(this, g, insets.left + IMAGE_WIDTH + SPACING, // 宽 insets.top); // 高 } } |
从上面的代码我们可以注意到在ProxyTest的构造函数中创建了一个ImageIcon对象和一个ImageIconProxy对象,并且重写了基类的paint()方法。在讨论代理类的实现代码之前,让我们先来看一下ImageIcon的类结构图:
 图3 ImageIcon的类结构图
从类结构图中可以看到,javax.swing.Icon接口中定义了三个最基本的方法:paintIcon(),getIconWidth()和getIconHeight()。ImageIcon类实现了Icon接口并且增加了一些方法。同时ImageIcon中也保存了对包含在其中的图形对象的引用以及描述。
ImageIcon代理类也实现了Icon接口,同时保存了对真实对象――ImageIcon的引用。图四显示了ImageIconProxy的类结构图。
 图4 ImageIconProxy的类结构图
下面是ImageIconProxy的实现代码:
例4 ImageIcon代理
// ImageIconProxy是ImageIcon对象的代理,它将图形的显示延迟到图形第一次被 // 绘制的时候。当图形还没有被绘制以前,该代理在界面上显示"加载图片…"的信息 class ImageIconProxy implements javax.swing.Icon { private Icon realIcon = null; boolean isIconCreated = false; private String imageName; private int width, height; public ImageIconProxy(String imageName, int width, int height){ this.imageName = imageName; this.width = width; this.height = height; } public int getIconHeight() { return isIconCreated ? height : realIcon.getIconHeight(); } public int getIconWidth() { return isIconCreated realIcon == null ? width : realIcon.getIconWidth(); } // 代理的paint()方法覆盖了积累中的该方法。注意代理直到在需要显示图形时才加 // 载了图形。 public void paintIcon(final Component c, Graphics g, int x, int y) { if(isIconCreated) { realIcon.paintIcon(c, g, x, y); } else { g.drawRect(x, y, width-1, height-1); g.drawString("加载图片...", x+20, y+20); // ImageIcon对象实在另一个线程中被创建的 synchronized(this) { SwingUtilities.invokeLater(new Runnable() { public void run() { try { // 为了使ImageIcon对象和ImageIcon代理之间的差别 // 更加显著,该线程休眠2秒 Thread.currentThread().sleep(2000); realIcon = new ImageIcon(imageName); isIconCreated = true; } catch(InterruptedException ex) { ex.printStackTrace(); } // 当创建了ImageIcon对象后调用repaint()方法重绘图形 c.repaint(); } }); } } } } |
ImageIconProxy通过realIcon保存了对一个对图形的引用。当第一次对代理进行绘制时,ImageIcon对象在一个独立的线程中被创建,然后图形被加载,并通过repaint()方法绘制。图五通过时序图说明了这些事件之间的关系。(未完待续)
|