Java与设计模式-代理模式

Posted yayun0516

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Java与设计模式-代理模式相关的知识,希望对你有一定的参考价值。

     代理模式也称为委托模式,属于结构型设计模式,为其他对象提供一种代理,以控制对这个对象的访问。这么听起来很难理解,生活中代理的例子也是很多的,毕业了要找房子,怎样又快又好的找到自己心仪的房子,必须通过租房代理;想要买火车票,火车站太远,我们可以选择代理点进行购票。代码模式的UML类图如下:

     应用场景:当无法或不想直接访问某个对象或访问某个对象存在困难时可以通过一个代理对象来间接访问,为了保证客户端使用的透明性,委托对象与代理对象需要实现相同的接口。下面我们以“秋菊打官司”为例,讲解一下代理模式。我们都知道在打官司时都要请一个律师,这个律师就可以认为是我们的代理,我们通过他进行某些操作。

     首先抽象类,打官司:

package com.proxy.demo;

public abstract class Lawsuit {
	/**
	 * 抽象类
	 */

	abstract void lawsuit();
}

    非常简单,就一个抽象方法,下面实现秋菊类,也就是真实类,覆写实现这个抽象方法:

package com.proxy.demo;

public class QiuJu extends Lawsuit {
	/**
	 * 真实类
	 */

	@Override
	void lawsuit() {
		System.out.println("我是秋菊,我要打官司!");

	}

}

     下面是代理类:

package com.proxy.demo;

public class ProxySubject {
	/**
	 * 代理类
	 */
	
	QiuJu qiuJu=null;
	
	public ProxySubject(QiuJu qiuJu) {//通过构造方法引入秋菊对象
		this.qiuJu=qiuJu;
	}
	
	public void lawsuit(){
		qiuJu.lawsuit();//代理帮秋菊打官司
	}

}

    代理类其实什么都没做,只是调用了真实类的方法。下面测试类:

package com.proxy.demo;

public class TestClass {

	public static void main(String[] args) {
		QiuJu qiuJu=new QiuJu();
		ProxySubject proxySubject=new ProxySubject(qiuJu);
		proxySubject.lawsuit();//通过代理调用方法

	}

}

     运行测试方法:

    我们可以看出,代理调用了真实类的方法,顺利实现了。这里顺便插一下,调整控制台字体大小的方法:

    打开window - preferences-- general - appearance - colors and fonts --debug - console font 就可以调节了

    代理模式是十分常用的方法,细心的朋友会发现,我们上一节文章《策略模式》就用到了代理模式。代理模式大致可以分为两个部分,一是静态代理,二是动态代理。上面讲的就是静态代理,代理者的代码由程序员自己或者通过一些自动化工具生成固定的代码再对其进行编译,也就是说,在我们的代码运行之前代理类的class编译文件就已经存在;而动态代码则是通过反射机制动态地生成代理者的对象,代理谁将会在执行阶段决定。Java也给我们提供了一个便捷的动态代理接口InvocationHandler,实现这个接口需要重写其调用方法invoke。也就是说,首先我们要完善这个动态代理类:

package com.proxy.demo;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;

public class DynamicProxy implements InvocationHandler {
	Object object=null;
	

	public DynamicProxy(Object object) {
		this.object = object;
	}


	@Override
	public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
		Object  result=method.invoke(object, args);
		return result;
	}

}

    Interface InvocationHandler:该接口中仅定义了一个方法Object:invoke(Object obj,Method method, J2EEjava语言JDK1.4APIjavalangObject.html">Object[] args)。在实际使用时,第一个参数obj一般是指代理类,method是被代理的方法,如上例中的request(),args为该方法的参数数组。这个抽象方法在代理类中动态实现。 
    原来在代理类中处理的事情交给InvocationHandler来处理,不再关心到底代理谁。

    下面修改测试类:

package com.proxy.demo;

import java.lang.reflect.Proxy;

public class TestClass {

	public static void main(String[] args) {
		/*
		 * QiuJu qiuJu=new QiuJu(); ProxySubject proxySubject=new
		 * ProxySubject(qiuJu); proxySubject.lawsuit();//通过代理调用方法
		 */
		Lawsuit lawsuit = new QiuJu();
		DynamicProxy dynamicProxy = new DynamicProxy(lawsuit);
		ClassLoader loader = lawsuit.getClass().getClassLoader();// 获取被代理类的ClassLoader
		// 动态构造一个代理律师对象
		Lawsuit lawyer = (Lawsuit) Proxy.newProxyInstance(loader, new Class[] { Lawsuit.class }, dynamicProxy);
		lawyer.lawsuit();

	}

}


    注意,由于动态代理需要,此时的Lawsuit变成了接口,QiuJu类变成实现接口。

    运行实例,和静态代理一样的结果:

    可以看出,动态代理类可以代理N个被代理类,其实质对代理类和被代理类进行解耦,使两者没有直接的解耦关系,使用时更灵活。而静态代理更符合面向对象的思想,在开发时可以根据需要实现代理。

 

 




 

 

以上是关于Java与设计模式-代理模式的主要内容,如果未能解决你的问题,请参考以下文章

java代理模式

Java代理设计模式与接口

java 查看寻呼机设计模式与片段。

代理模式

Java设计模式之代理模式

Java RMI地址解析问题