• 热门专题

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

作者:  发布日期:2015-12-15 20:22:55
Tag标签:设计模式  模式  
  • 这里只是简单的介绍下最基本的代理的使用。

     

    代理,通俗点说 :就是一个人或者一个机构代表另一个人或者另一个机构采取行动。在一些情况下,一个客户不想或者不能够直接引用一个对象,而代理对象可以在客户端和目标对象之前起到中介的作用。
    代理模式给某一个对象提供一个代理对象,并由代理对象控制对原对象的引用。

    UML图

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

     抽象对象角色:声明了目标对象和代理对象的共同接口,这样一来在任何可以使用目标对象的地方都可以使用代理对象。

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

    代理对象角色:代理对象内部含有目标对象的引用,从而可以在任何时候操作目标对象;代理对象提供一个与目标对象相同的接口,以便可以在任何时候替代目标对象。代理对象通常在客户端调用传递给目标对象之前或之后,执行某个操作,而不是单纯地将调用传递给目标对象。

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

    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,实现对象 Connection con=DriverManager.getConnection(url, user, password);//在进行连接的时候可以。

    3,需要我们的代理类。

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

     

    public class hibernateFactory2 {
    	private static final int NUM=3;
    	private static List<Connection> pool =new ArrayList<Connection>();
    	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;i<NUM;i++){
    					final Connection	con=DriverManager.getConnection(url, user, password);
    					//采用动态代理开始进行对connection接口实现代理,对con.close,实现换回去
    					Object 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),这不难理解。复杂隐藏代理和外观模式是不一样的,因为代理控制访问,而外观模式是不一样的,因为代理控制访问,而外观模式只提供另一组接口。

About IT165 - 广告服务 - 隐私声明 - 版权申明 - 免责条款 - 网站地图 - 网友投稿 - 联系方式
本站内容来自于互联网,仅供用于网络技术学习,学习中请遵循相关法律法规