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

 

 




 

 

  • 4
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 5
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值