【代理模式】静态代理与动态代理

代理模式:通过代理类对目标类进行包装。

代理类、目标类要具有一样的功能,实现共同的接口。用户只能看到代理类,实际上是通过代理类与目标类进行交互。

静态代理模式:每个代理类只代理一个目标类


实现相同的接口,代理类中持有一个目标类的对象的引用,通过构造器为目标类赋值。


案例如下:

Demo类:

public class Demo {
	public static void main(String[] args){
		//静态代理,FactoryProxy只能单独代理FactoryImpl类
		FactoryProxy factoryProxy = new FactoryProxy(new FactoryImpl());
		System.out.println(factoryProxy.produc());
	}
}

共同实现的接口:

public interface Factory {
	String produc();
}


工厂实现类:

public class FactoryImpl implements Factory {

	@Override
	public String produc() {
		String str = "生产的字符串";
		return str;
	}

}


工厂代理类:

public class FactoryProxy implements Factory {
	//代理类中持有的目标类对象
	private FactoryImpl factoryImpl;
	//通过构造方法新建目标类对象
	public FactoryProxy(FactoryImpl factoryImpl) {
		this.factoryImpl = factoryImpl;
	}
	
	@Override
	public String produc() {
		String str = "经过代理后 " + factoryImpl.produc();
		return str;
	}
}

静态代理程序运行结果:

经过代理后 生产的字符串


静态代理模式每次增加新的目标类都必须增加配套的代理类,当目标类较多时程序会过于复杂,工程量大,此时建议使用动态代理模式。



动态代理模式:动态代理多个类


使用ProxyHandler类动态代理多个类。ProxyHandler类持有一个Object对象,通过构造器初始化Object对象。实现了InvocationHandler接口。重写了invoke方法。


案例如下:


Demo类:

import java.lang.reflect.Proxy;

public class Demo {

	public static void main(String[] args) {
		
		System.out.println("测试类1:Count接口实现类\n");
		
		CountImpl countImpl = new CountImpl();
		ProxyHandler ph = new ProxyHandler(countImpl);
		//newProxyInstance返回一个指定接口的代理类实例,该接口可以将方法调用指派到指定的调用处理程序。
		/*
		  	参数:
			loader - 定义代理类的类加载器
			interfaces - 代理类要实现的接口列表
			h - 指派方法调用的调用处理程序 
		 */
		Count count = (Count) Proxy.newProxyInstance(countImpl.getClass().getClassLoader(), 
						<span style="white-space:pre">	</span>     countImpl.getClass().getInterfaces(), 
							     ph);
		//调用add()
		int result = count.add(5, 10);
		System.out.println("调用add方法结果: "+result);
		System.out.println("\n---------------------------------\n");
		//调用print()
		String result2 = count.print();
		System.out.println("调用print方法结果: "+result2);
		
		//测试其他目标类
		System.out.println("\n测试类2:GetSet接口实现类\n");
		
		GetSetImpl getsetImpl = new GetSetImpl();
		ProxyHandler phGC = new ProxyHandler(getsetImpl);
		
		GetSet getset = (GetSet) Proxy.newProxyInstance(getsetImpl.getClass().getClassLoader(),
								getsetImpl.getClass().getInterfaces(), 
								phGC);
		//调用set()
		getset.set('X');
		System.out.println("\n---------------------------------\n");
		//调用get()
		char c = getset.get();
		System.out.println("Get: "+c);
	}
}


ProxyHandler类:

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

public class ProxyHandler implements InvocationHandler {
	//目标类的对象,由于需要所有的类都能用当前的类来代理,所以创建一个Object对象
	private Object obj;
	//假设代理的是CountImpl,若调用里面的方法。多个方法可以看接口中的方法列表
	public ProxyHandler(Object obj) {
		this.obj = obj;
	}

	/**
	 * 在代理实例上处理方法调用并返回结果。
	 * 	proxy -  在其上调用方法的代理实例
		method - 对应于在代理实例上调用的接口方法的 Method 实例。
		     Method 对象的声明类将是在其中声明方法的接口,该接口可以是代理类赖以继承方法的代理接口的超接口。
		args -   包含传入代理实例上方法调用的参数值的对象数组,如果接口方法不使用参数,则为 null。
		     基本类型的参数被包装在适当基本包装器类(如 java.lang.Integer 或 java.lang.Boolean)的实例中。 
	 * 
	 */
	@Override
	public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {

		System.out.println("调用的方法: "+method);
		System.out.println("方法参数列表: "+Arrays.toString(args));
		//调用此方法
		Object result = method.invoke(obj, args);
		return result;
	}
}

测试对象类接口1:
public interface Count {
	int add(int a, int b);
	String print();
}

测试对象目标类1:

public class CountImpl implements Count{

	@Override
	public int add(int a, int b){
		System.out.println("目标类CountImpl做的工作: a+b");
		return a+b;
	}

	@Override
	public String print() {
		System.out.println("目标类CountImpl做的工作: print");
		return "This is Class CountImpl";
	}
}

测试对象类接口2:

public interface GetSet {
	char get();
	void set(char c);
}


测试对象目标类2:

public class GetSetImpl implements GetSet {
	private char temp;
	@Override
	public char get() {
		return this.temp;
	}

	@Override
	public void set(char c) {
		this.temp = c;
	}
}

动态代理程序运行结果:


测试类1:Count接口实现类


调用的方法: public abstract int trends_proxy.Count.add(int,int)
方法参数列表: [5, 10]
目标类CountImpl做的工作: a+b
调用add方法结果: 15

---------------------------------

调用的方法: public abstract java.lang.String trends_proxy.Count.print()
方法参数列表: null
目标类CountImpl做的工作: print
调用print方法结果: This is Class CountImpl


测试类2:GetSet接口实现类

调用的方法: public abstract void trends_proxy.GetSet.set(char)
方法参数列表: [X]

---------------------------------

调用的方法: public abstract char trends_proxy.GetSet.get()
方法参数列表: null
Get: X

当需要增加新的目标类时,只需要添加目标类接口及其实现类,在使用时通过ProxyHandler类代理即可,不需要增加额外的代理类。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值