代理模式-结构型模式1

即Proxy Pattern,23种java常用设计模式之一。代理模式的定义:为其他对象提供一种代理以控制对这个对象的访问。在某些情况下,一个对象不适合或者不能直接引用另一个对象,而代理对象可以在客户端和目标对象之间起到中介的作用。

定义:

为其他对象提供一种代理以控制对这个对象的访问。

结构:

代理模式-结构型模式1

说明:

Proxy:代理对象,通常具有如下功能:

实现与具体的目标对象一样的接口,这样就可以使用代理来代替具体的目标对象

保存一个指向具体目标对象的引用,可以在需要的时候调用具体的目标对象

可以控制对具体目标对象的访问,并可能负责创建和删除它

Subject:目标接口,定义代理和具体目标对象的接口,这样就可以在任何使用具体目标对象的地方使用代理对象

RealSubject:具体的目标对象,真正实现目标接口要求的功能。

具体代码:

/**
 * 抽象的目标接口,定义具体的目标对象和代理公用的接口
 */
public interface Subject {
	/**
	 * 示意方法:一个抽象的请求方法
	 */
	public void request();
}

/**
 * 具体的目标对象,是真正被代理的对象
 */
public class RealSubject implements Subject {

	public void request() {
		//执行具体的功能处理
	}

}

/**
 * 代理对象
 */
public class Proxy implements Subject {
	/**
	 * 持有被代理的具体的目标对象
	 */
	private RealSubject realSubject = null;

	/**
	 * 构造方法,传入被代理的具体的目标对象
	 * @param realSubject 被代理的具体的目标对象
	 */
	public Proxy(RealSubject realSubject) {
		this.realSubject = realSubject;
	}

	public void request() {
		//在转调具体的目标对象前,可以执行一些功能处理

		//转调具体的目标对象的方法
		realSubject.request();

		//在转调具体的目标对象后,可以执行一些功能处理
	}

}


代理(Proxy)有两种:

静态代理-Static proxy

动态代理-Dynamic proxy

具体案例:

1. 静态代理

为实现静态代理需要为HelloSpeaker写一个HelloProxy类,同样实现IHello接口,并在hello方法执行log,并执行HelloSpeaker的hello()方法。

/**
 * 此处可以为接口也可以为抽象类
 * @author ljn
 *
 */
public interface IHelloSpeaker {
	public abstract void hello();
}

/**
 * 接口实现类日志功能  简单的打印一句话
 * @author ljn
 *
 */
public class HelloSpeaker implements IHelloSpeaker {
	public void hello(){
		System.out.println("............this is Log");
	}
}

/**
 * 代理类实现IHelloSpeaker接口,同时拥有实际对象的引用(private HelloSpeaker helloObj;//代理类内部引用真实类)
 * 代理必须完成委托对象的动作,也可以添加自己的动作(doBefore,doAfter)。
 * 
 * @author ljn
 * 
 */
public class HelloProxy implements IHelloSpeaker {

	private HelloSpeaker helloObj;// 代理类内部引用委托类

	public HelloProxy(HelloSpeaker helloSpeaker) {
		this.helloObj = helloSpeaker;
	}

	private void doBefore() {
		System.out.println("method doBefore invoke!");
	}

	private void doAfter() {
		System.out.println("method doAfter invoke!");

	}

	@Override
	public void hello() {
		// TODO Auto-generated method stub
		doBefore();// 其他业务逻辑
		helloObj = new HelloSpeaker();
		helloObj.hello();// 委托类具体的业务逻辑。
		doAfter();// 其他业务逻辑
	}
}
/**
*测试类
*/
public class Test {
	public static void main(String[] args) {
//其中HelloProxy中helloObject为需要代理的对象,在其它地方如下来使用代理机制
		IHelloSpeaker proxy = new HelloProxy(new HelloSpeaker());
		proxy.hello();
	}
}

2:动态代理:

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

public class LogHandler implements InvocationHandler { 
    
    private Object delegate;

    public Object bind(Object delegate) { 
        this.delegate = delegate; 
        return Proxy.newProxyInstance( 
                           delegate.getClass().getClassLoader(), 
                           delegate.getClass().getInterfaces(), 
                           this); 
    }

	@Override
	public Object invoke(Object proxy, Method method, Object[] args)
			throws Throwable {
		Object result = null;         
        try { 
            System.out.println("method starts..."+method);
            result = method.invoke(delegate, args);
            System.out.println("method starts..."+method);
        } catch (Exception e){ 
            e.printStackTrace();
        }        
        return result; 
	}
}
//测试程序
public static void main(String[] args) {
        LogHandler logHandler  = new LogHandler(); 
        
        IHelloSpeaker helloProxy = 
                (IHelloSpeaker) logHandler.bind(new HelloSpeaker()); 
        helloProxy.hello();
    }

使用场景:

当客户端代码需要调用某个对象时,客户端实际上也不关心是否准确得到该对象,它只要一个能提供该功能的对象即可,此时我们就可返回该对象的代理(Proxy)。

      实际用例:

看到此处,相信读者应该对Spring的AOP框架有点感觉了:当Spring容器中的被代理Bean实现了一个或多个接口时,Spring所创建的AOP代理就是这种动态代理。Spring AOP与此示例应用的区别在哪里呢?Spring AOP更灵活,当Sping定义InvocationHandler类的invoke()时,它并没有以硬编码方式决定调用哪些拦截器,而是通过配置文件来决定在invoke()方法中要调用哪些拦截器,这就实现了更彻底的解耦——当程序需要为目标对象扩展新功能时,根本无须改变Java代理,只需要在配置文件中增加更多的拦截器配置即可。

优点和缺点:

1) 优点: 向客户端隐藏了访问某个对象的细节及复杂性;可以动态地调用一个对象中的方法,且无需实现固定的接口。

留给自己的问题:

spring的aop,hibernate,mybatis的懒加载应用代理模式

你可能感兴趣的:(代理模式-结构型模式1)