薛磊 Job Seeker

23种设计模式——12.Proxy 代理(结构型模式)


直接与间接

  人们对于复杂的软件系统常常有一种处理手法,即增加一层间接层,从而对系统获得一种更为灵活、满足特定需求的解决方案。

动机(Motivation)

  在面向对象系统中,有些对象由于某种原因(比如对想创建的开销很大,或者某些操作需要安全控制,或者需要进程外的访问等,直接访问会给使用者、或者系统结构带来很多麻烦。

  如何在不失去透明操作对象的同时来管理/控制这些对象特有的复杂性?增加一层间接层是软件开发中常见的解决方式。

结构(Structure)

普通代理和强制代理

  普通代理:它的要求是客户端只能访问代理角色,不能访问真实角色

  强制代理:必须通过真实角色查找到代理角色,也就是说由真实角色管理代理角色。

Proxy模式的几个要点

  • “增加一层间接层”是软件系统中许多复杂问题的一种常见解决方法。在面向对象系统中,直接使用某些对象会带来很多问题,作为间接层的proxy对象便是解决这一问题的常用手段。

  • 具体proxy设计模式的实现方法、实现粒度都相差很大,有些可能对单个对象做细粒度的控制,如copy-on-write技术,有些可能对组件模块提供抽象代理层,在架构层次对对象做proxy。

  • proxy并不一定要求保持接口的一致性,只要能够实现间接控制,有时候损及一些透明性是可以接受的。

静态代理类似于装饰者模式。

动态代理

  面向横切面编程,也就是AOP,其核心就是采用了动态代理机制。

结构:

  动态代理实现代理的职责,业务逻辑Subject实现相关的逻辑功能,两者之间没有必然的相互耦合的关系。

示例代码(动态代理):

抽象主题:

public interface Subject{
	public void doSomething(String str);
}

真实主题:

public class RealSubject implements Subject{
	public void doSomething(String str){
		System.out.println("do something!"+str);
	}
}

动态代理的Handler类:

public class MyInvocationHandler implements InvocationHandler{
	//被代理的对象
	private Object target = null;
	//通过构造函数传递一个对象
	public MyInvocationHandler(Object obj){
		this.target = obj;
	}
	/代理方法
	public Object invoke(Object proxy ,Method method,Object[] objs) thows Throwable{
		//执行被代理的方法
		return method.invoke(this.target,objs);
	}
}

动态代理类:

public class DynamicProxy<T>{
	public static <T> T newProxyInstance(ClassLoader loader,Class<?>[] interfaces,InvocationHanler h){
		//寻找JoinPoint连接点,AOP框架使用元数据定义
		if(true){
			//执行一个前置通知
			(new BeforeAdvice()).exec();
		}
	}
	//执行目标,并返回结果
	return (T)Proxy.newProxyInstance(loader,interfaces,h);
}

具体业务的动态代理:

public class SubjectDynamicProxy extends DynamicProxy{
	public static <T> newProxyInstance(Subject subject){
		//获得ClassLoader
		ClassLoader loader = subject.getClass().getClassLoader();
		//获得接口数组
		Class<?>[] classes = subject.getClass().getInterfaces(;
		//获得handler
		InvocationHandler handler = new MyInvocationHandler(subject);
		return newProxyInstance(loader,classes,handler);
	}
}	

场景类:

public class Client{
	public static void main(Stirng[] args){
		//定义一个主题
		Subject subject = new RealSubject();
		//定义主题的代理
		Subject proxy = SubjectDynamicProxy.newProxyInstance(subject);
		//代理的行为
		proxy.doSomething("Finish");
	}
}

Comments

Content