设计模式之代理模式

代理模式,从起名字我们就可以猜出一二,意思是A要调用对象B,处于某些原因,不便于直接接触,而通过proxy代理类来代为调用。其原因主要可以归为如下几类:

1. B类封装的要求,不便于客户程序了解太多。用来控制真实对象时的访问权限(安全代理)

2. A调用远程对象B,多有不便,因此在本地建造Proxy代为处理,A直接调用Proxy,就像操作本地对象。(远程代理)

3. A在调用B前和B后要做一些必要的其他工作,使用代理类就可以把这些功能封装在一起。(职能指引)

4. B构建和初始化费时费力,创建虚拟代理存放其实例。(虚拟代理)


代理模式的简单类图表示如下:


在上图中,代理类和真实类都继承至同一接口,并且代理类中存在真实类的实例。


在java多线程中, Thread t = new Thread(new Runnable(){public void run(){}}); 则是典型的代理模式。 这种设计的目的使得创建多线程的方式便的更加灵活。与上面代理模式的典型类图有所差异, Runnable为接口,Thread继承至Runnable。

public Thread(Runnable target) {
	init(null, target, "Thread-" + nextThreadNum(), 0);
    }

public synchronized void start() {
        /**
	 * This method is not invoked for the main method thread or "system"
	 * group threads created/set up by the VM. Any new functionality added 
	 * to this method in the future may have to also be added to the VM.
	 *
	 * A zero status value corresponds to state "NEW".
         */
        if (threadStatus != 0)
            throw new IllegalThreadStateException();
        group.add(this);
        start0();
        if (stopBeforeStart) {
	    stop0(throwableFromStop);
	}
    }

    private native void start0();

    public void run() {
	if (target != null) {
	    target.run();
	}
    }

从代码中可以看到,通过start()启动线程后,在start()中会调用本地方法start0(), 该方法会在底层完成线程初始化工作并最终调用run()启动线程, 在run()中则调用了构造方法中传递的Runnable对象。

这里再举一个因为B对象加载缓慢(即虚拟代理)而使用代理的例子。例子来源于《Java与模式》,自己感觉这本书虽然没有太大价值,但是这个例子还是能说明一些问题的。

package learn.sync;

import java.awt.Graphics;
import java.awt.Insets;

import javax.swing.Icon;
import javax.swing.JFrame;

public class Client extends JFrame{

	private static int WIDTH = 270;
	private static int HEIGHT = 380;
	private Icon imageIcon = null;
	/**
	 * @param args
	 */
	public static void main(String[] args) {
		// TODO Auto-generated method stub
		Client client = new Client();
		client.setVisible(true);
	}
	
	public Client(){
		super("proxy example");
		imageIcon = new ImageIconProxy("E:\\xx.jpg",WIDTH,HEIGHT);
		this.setBounds(100, 100, WIDTH+10, HEIGHT+10);
		this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
	}
	
	public void paint(Graphics g)
	{
		super.paint(g);
		Insets inset = this.getInsets();
		imageIcon.paintIcon(this, g,inset.left , inset.top);
	}

}

package learn.sync;

import java.awt.Component;
import java.awt.Graphics;

import javax.swing.Icon;
import javax.swing.ImageIcon;
import javax.swing.SwingUtilities;

public class ImageIconProxy implements Icon {

	private ImageIcon icon;
	private String path;
	private int width;
	private int height;
	private boolean isFinish = false;
	
	public ImageIconProxy(String path, int width, int height){
		this.path = path;
		this.width = width;
		this.height = height;
	}
	@Override
	public int getIconHeight() {
		// TODO Auto-generated method stub
		return icon.getIconHeight();
	}

	@Override
	public int getIconWidth() {
		// TODO Auto-generated method stub
		return icon.getIconWidth();
	}

	@Override
	public void paintIcon(final Component c, Graphics g, int x, int y) {
		// TODO Auto-generated method stub
		if(isFinish){
			icon.paintIcon(c, g, x, y);
		}
		else
		{
			g.drawRect(x, y, width-1, height-1);
			g.drawString("loading", x+10, y+10);
			
			/*
			synchronized(this){
				SwingUtilities.invokeLater(new Runnable(){
					public void run(){
						try {
							Thread.currentThread().sleep(5000);
						} catch (InterruptedException e) {
							// TODO Auto-generated catch block
							e.printStackTrace();
						}
						icon = new ImageIcon(path);
						isFinish = true;
						c.repaint();
					}
				});
			}*/
			
			Thread t = new Thread(){
				public void run(){
					try {
						Thread.currentThread().sleep(5000);
					} catch (InterruptedException e) {
						// TODO Auto-generated catch block
						e.printStackTrace();
					}
					icon = new ImageIcon(path);
					isFinish = true;
					c.repaint();
				}
			};
			t.setDaemon(true);
			t.start();
			
		}
	}

其中,上面代码的注释部分是原书中的代码,认为SwingUtilities.invokerLater()是开启独立的新线程,本人觉得是完全错误的。 该方法是加入事件派发线程的,swing是单线程的图形API,读者如果不了解这一部分,需要认真看一下,许多人都没能正确理解。 这种与界面无关的耗时操作应该放在新的线程中,不然会阻塞当前窗口,使得窗口不能响应事件,所以这里我又建了一个新线程。

这里,我们可以清楚的看到代理类为ImageIconProxy ,而实际类则是ImageIcon icon,作为成员存在于ImageIconProxy。代理类完成缓冲提示,加载,最终调用ImageIcon的paintIcon方法绘制图片。


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值