JAVA设计模式之----------代理模式(Proxy)

这里只是简单的介绍下最基本的代理的使用。


代理,通俗点说 :就是一个人或者一个机构代表另一个人或者另一个机构采取行动。

在一些情况下,一个客户不想或者不能够直接引用一个对象,而代理对象可以在客户

端和目标对象之前起到中介的作用。
代理模式给某一个对象提供一个代理对象,并由代理对象控制对原对象的引用。


UML图

JAVA设计模式之----------代理模式(Proxy)_第1张图片

从上面的图我们能看到代理涉及的角色:

 抽象对象角色:声明了目标对象和代理对象的共同接口,

这样一来在任何可以使用目标对象的地方都可以使用代理对象。

  目标对象角色:定义了代理对象所代表的目标对象。(也就是要代理的是谁)

            代理对象角色:代理对象内部含有目标对象的引用,从而可以在任何时候

操作目标对象;代理对象提供一个与目标对象相同的接口,以便可以在任何时候替代目标对象。

代理对象通常在客户端调用传递给目标对象之前或之后,执行某个操作,而不是单纯地将调用

传递给目标对象。    


我们在这里演示一个房东,中介和客户之间的关系(中介就是代理)

1,我们需要一个抽象的对象角色:(接口)

public interface IRenter {
	public abstract void rent();
}

2,我们需要的目标对象:(就是实现的接口的类)

public class Renter implements IRenter{
	@Override
	public void rent() {
		System.out.println("我是房东,开始收费咯咯");
	}
}


3,代理对象的角色(就是我们的代理)

我们需要用到这个Java中代理使用的类

Object o =Proxy.newProxyInstance(loader, interfaces, h)

public class Client {
	
	@Test
	public void Test2(){
		 final Renter r =new Renter();//被代理的对象
		//o是中介代理之后的对象
		Object o =Proxy.newProxyInstance(Client.class.getClassLoader(),
								new Class[]{IRenter.class},new InvocationHandler() 								{
									@Override
									public Object invoke(Object proxy, Method method, Object[] args)
											throws Throwable {
		//从这里开始就是开始拦截要控制的内容了,如if(method.getName.equals('rent')){将方法名为rent的函数,做出你想要的事情}
//										System.out.println("aaaa");//这里只是简单的每个方法之前输出
										System.out.println("收点费用");
										return method.invoke(r, args); //return method.invoke(要代理的对象, 参数传进来什么参数就放出什么参数,这里相当于全部放开);

									}
								} );
		IRenter ir =(IRenter) o;//最后在使用的时候需要  将对象  强转为接口类型的
		ir.rent();
	}
}

通过上面的简单介绍,能发现,一个代理类的所有方法或函数,都要经过代理之后,才会进行操作,指定操作的方法做我们想做的事情,没有指定的直接放行

上面的只是一个简单的介绍例子,下面介绍一个在实际中的使用例子。

我们在连接数据库的时候,都是采用的链接池的方式,但是链接池里面的连接都是有限个的,

所以我们需要每个用完之后就将其放回池中,但是单独去写一个函数将其放回池中,不太好用,

所以,我们就将 con.close()关闭连接的时候,不去关,而是直接的放回池中,

让其他的线程来调用,也就是需要拦截con里面的close方法。

所需要的三个角色:

1,接口对象  connection接口

2,实现对象   Connectioncon=DriverManager.getConnection(url, user, password);//在进行连接的时候可以。

3,需要我们的代理类。

下面这是整个连接池的代码:

public class hibernateFactory2 {
	private static final int NUM=3;
	private static List pool =new ArrayList();
	static{
		//读取配置文件
		Properties p =new Properties();		
			try {
				p.load(hibernateFactory.class.getClassLoader().getResourceAsStream("jdbc.properties"));
				//读取里面的值,一直修改配置文件即可
				String driver=p.getProperty("driver");
				String url=p.getProperty("url");
				String user=p.getProperty("username");
				String password=p.getProperty("password");
				System.out.println(driver+url+user+password);
				Class.forName(driver);
				for(int i=0;iObject o =Proxy.newProxyInstance(hibernateFactory2.class.getClassLoader(), new Class[]{Connection.class},
							new InvocationHandler() {
								@Override
								public Object invoke(Object proxy, Method method, Object[] args)
										throws Throwable {
									if(method.getName().equals("close")){ //拦截close方法
										pool.add((Connection)(proxy));//将连接还回池
										System.out.println("换回来了。。。");
										return null;
									}
									return method.invoke(con, args);//其余的全部放行
								}
							});
					pool.add((Connection)o);
				}
			//	System.out.println("初始化完毕"+con);
			} catch (IOException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			} catch (SQLException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			} catch (ClassNotFoundException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
			
	}
	//下面是获取连接。
	public static synchronized Connection getCon() throws Exception{
		if(pool.size()<=0){
			System.out.println("pool中已经没有连接");
			return getCon() ;
		}
		System.out.println("使用一个。。");
		return  pool.remove(0); 
		//两种方法都是可以的
//		while(pool.size()<=0){
//			System.out.println("池中已经乜有连接");
//			Thread.sleep(1000);
//		}
//		return pool.remove(0);
//	}
	
}}


在上面的基础上,我们写了一个通用的版本

public class proxyUtils {
	
	public static Object getProxy(final Object srcobj){
		Object o = Proxy.newProxyInstance(proxyUtils.class.getClassLoader(),
							srcobj.getClass().getInterfaces(), //这句可以修改
							new InvocationHandler() {
								
								@Override
								public Object invoke(Object proxy, Method method, Object[] args)
										throws Throwable {
									System.out.println("被拦击了。。。。");//这里采用拦截
									return  method.invoke(srcobj, args);//返回值我们也可以进行一些列的操作
								}
							}
				);
		return o;
	}
}
但是我们在调用的这个工具的时候,必须传进来一个实例对象,也就是实现了的类

如 IA 为接口 A 为实现类

A a =new A();

IA ia =(IA)proxyUtils.getProxy(a);

通过ia 的对象调用方法就可以。


上面方法的另一种实现形式

public class proxyUtils2 implements InvocationHandler{
	private Object srcobj;
	public proxyUtils2(Object srcobj) {
		this.srcobj=srcobj;
	}	
	public static Object getProxy(final Object srcobj){
		Object o = Proxy.newProxyInstance(proxyUtils2.class.getClassLoader(),
							srcobj.getClass().getInterfaces(), //这句可以修改 ,在不知道的情况下,这种方法最好 
							new proxyUtils2(srcobj));				
		return o;
	}
	@Override
	public Object invoke(Object proxy, Method method, Object[] args)
			throws Throwable {
			System.out.println("在这里采用拦截");
			Object obj =method.invoke(srcobj, args);//在这里我们还可以进行对返回的值进行操作,这也是代理带来的好处
			return obj;	
	}
}

上面的这些都是采用代理设计模式实现的,其实 代理模式就相当于一个秘书,能帮你做你想做的事情。


代理应用方面(从别人哪里看到的)

 代理模式的应用形式

(1)远程代理(Remote Proxy) -可以隐藏一个对象存在于不同地址空间的事实。也使得客户端可以访问在远程机器上的对象,远程机器可能具有更好的计算性能与处理速度,可以快速响应并处理客户端请求。

(2)虚拟代理(Virtual Proxy) – 允许内存开销较大的对象在需要的时候创建。只有我们真正需要这个对象的时候才创建。

(3)写入时复制代理(Copy-On-Write Proxy) – 用来控制对象的复制,方法是延迟对象的复制,直到客户真的需要为止。是虚拟代理的一个变体。

(4)保护代理(Protection (Access)Proxy) – 为不同的客户提供不同级别的目标对象访问权限

(5)缓存代理(Cache Proxy) – 为开销大的运算结果提供暂时存储,它允许多个客户共享结果,以减少计算或网络延迟。

(6)防火墙代理(Firewall Proxy) – 控制网络资源的访问,保护主题免于恶意客户的侵害。

(7)同步代理(SynchronizationProxy) – 在多线程的情况下为主题提供安全的访问。

(8)智能引用代理(Smart ReferenceProxy) - 当一个对象被引用时,提供一些额外的操作,比如将对此对象调用的次数记录下来等。

(9)复杂隐藏代理(Complexity HidingProxy) – 用来隐藏一个类的复杂集合的复杂度,并进行访问控制。有时候也称为外观代理(Façade Proxy),这不难理解。复杂隐藏代理和外观模式是不一样的,因为代理控制访问,而外观模式是不一样的,因为代理控制访问,而外观模式只提供另一组接口。


你可能感兴趣的:(设计模式,JAVAEE学习记录)