模式的秘密——代理模式

最近在慕课网上看了一下代理模式的课程,这里进行一些总结

代理模式

1.什么是代理模式?

   为其他对象提供一种代理以控制对这个被代理对象的访问,代理对象起到一个中介的作用,可以去掉功能服务或增加额外的服务

    其实简单点说,就是代理对象帮被代理对象处理业务,同时也加上一些自己的业务


2.代理模式分类:

    1.远程代理(Remote Proxy):为不同地理的对象提供局域网代表对象    

    例:通过远程代理监控各个连锁店铺,使其能直观的了解店内信息

    2.虚拟代理(virtual Proxy):根据需要将资源消耗很大的对象进行延迟,真正需要的时候进行创建              

      例:浏览页面,图片展示部分使用虚拟代理显示,当真实的图片加载完成后显示真实的图片   

    3.保护代理(Protect Proxy/Access Proxy):控制对象的访问权限   

    例:网上有些内容或模块必须要注册登录之后才能浏览或操作

    4.智能引用代理(Smart Reference Proxy):当一个对象被引用时,提供一些额外的操作 

    例:火车票代售处

3.静态代理和动态代理

    1.静态代理

     静态代理:代理和被代理对象在【代理之前】都是【确定】的。他们都实现【相同的接口或者继承相同的抽象类】

     示例:

这里定义一个接口

   package com.hxkj.proxy;
 /**
     * 行驶的接口
 * @author Administrator
 *
 */
public interface Moveable {


//move方法
void move();
}

创建一个Car类实现接口

package com.hxkj.proxy;


import java.util.Random;


/**
 * 汽车类实现行驶的接口
 * @author wanbin
 *
 */
public class Car implements Moveable {


@Override
public void move() {

//汽车行驶0-1000以内毫秒数的时间后开始行驶
try {
Thread.sleep(new Random().nextInt(1000));
    } catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println("汽车行驶中......");
}


}

创建一个代理类

package com.hxkj.proxy;
/**
 * 通过聚合完成静态代理
 * 什么是聚合? 聚合就是在一个类中调用另一个类
 * @author wangbin
 *
 */
public class CarLogProxy implements Moveable {


private Moveable moveable;

public CarLogProxy(Moveable moveable) {

this.moveable = moveable;
}


@Override
public void move() {
// TODO Auto-generated method stub
System.out.println("汽车日志开始......");
moveable.move();
System.out.println("汽车日志结束.......");
}


}

创建一个测视类

package com.hxkj.proxy;
/**
 * 测试类
 * @author wangbin
 *
 */
public class Test {


public static void main(String[] args) {

// Car car = new Car();
// car.move();
//通过继承的方式完成静态代理
// Car2 car2 = new Car2();
// car2.move();
//通过聚合的方式完成静态代理
// Car car = new Car();
// CarTimeProxy car3 = new CarTimeProxy(car);
// car3.move();
//通过聚合方式实现不同代理类功能的叠加,还可以交换顺序
Car car = new Car();
CarTimeProxy ctp = new CarTimeProxy(car);
CarLogProxy clp = new CarLogProxy(ctp);
clp.move();
}

}

实现静态代理有两种方式:一种是继承,一种是聚合

不推荐使用继承的的方式,因为每次要添加新的业务功能就需要写写的代理类,这样很容易造成类膨胀

使用聚合的方式可以将代理类进行复用进行业务功能的增强,而且还可以调整业务顺序

    2.动态代理

    JDK动态代理:代理对象和被代理对象不确定的,但是都实现了相同的接口或者继承了相同的抽象类,动态产生代理,实现对【不同类】,【不同方法】的代理

java动态代理类,位于java.lang.reflect包下,一般涉及两个类:
(1)Interface InvocationHandler:该接口中仅定义了一个方法public object invoke(obj,method,args):实际使用中,obj指代理的对象,method代理对象的方法,
args为该方法参数数组。这个抽象方法在代理类中动态实现
(2)Proxy:该类即为动态代理类:static Object newProxyInstance(ClassLoader loader,Class[] interfaces,InvocationHandler h):返回代理类的一个实例,返回后的代理类可以被当作代理类使用(可使用被代理类的在【接口中】声明过的方法)。
· 第一个参数loader为被代理类的加载器,通过被代理类.getClass().getClassLoader()得到
· 第二个参数interfaces为被代理类实现的所有接口,同样通过getClass().getInterface()得到
· 第三个参数handler就是自己实现的InvocationHandler的实现类的对象,(时间、日志等拦截器)
3、***实现:
· 声明一个代理h实现InvocationHandler接口,通过【构造方法接受被代理类】,并实现invoke方法,添加业务逻辑(实现原有功能并添加额外功能)
· 在测试类中,通过共同实现接口的实例获得代理对象,并实现方法,如Interface1 i = (Interface1)Proxy.newProxyInstance(classLoader,classInterfaces,h);
· 通过动态代理对象m,代用其方法i.fun();

            

注意:当代理对象调用真实对象的方法时,其会自动的跳转到代理对象关联的handler对象的invoke方法来进行调用

            System.out.println("在被代理对象方法被调用前需要执行的代码")

               method.invoke(obj);

            System.out.println("在被代理对象方法被调用后需要执行的代码")

代码示例:

同样是这个接口


package com.hxkj.proxy;
/**
 * 行驶的接口
 * @author Administrator
 *
 */
public interface Moveable {


//move方法
void move();
}

Car类实现接口

package com.hxkj.proxy;


import java.util.Random;


/**
 * 汽车类实现行驶的接口
 * @author wanbin
 *
 */
public class Car implements Moveable {


@Override
public void move() {

//汽车行驶0-1000以内毫秒数的时间后开始行驶
try {
Thread.sleep(new Random().nextInt(1000));
    } catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println("汽车行驶中......");
}


}

创建时间拦截器

package com.hxkj.jdkproxy;


import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
/**
 * JDK的动态代理
 * 这是一个时间处理器,实现InvocationHandler接口
 * @author wangbin
 *
 */
public class TimeHandler implements InvocationHandler {


private Object obj;//被代理对象
//传入被代理对象构造这个业务处理器
public TimeHandler(Object obj) {
this.obj = obj;
}


/**
* 这里用的是反射原理
* 参数:
* proxy:代理对象
* method:被代理对象的方法
* args:方法的参数
* 返回值:
* Object 方法的返回值

*/


@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
// TODO Auto-generated method stub
/**
* 在代理类中增加新的业务功能
*/
System.out.println("在被代理对象方法被调用前新增的业务逻辑");
/**
* 通过反射调用被代理对象的方法
*/
method.invoke(obj);

System.out.println("在被代理对象方法被调后前新增的业务逻辑");

return null;
}


}

创建日志拦截器

package com.hxkj.jdkproxy;


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


public class LogHandler implements InvocationHandler {


private Object obj;//被代理对象
//传入被代理对象构造业务处理器对象
public LogHandler(Object obj) {
this.obj = obj;
}


/**
* 这里用的是反射原理
* 参数:
* proxy:代理对象
* method:代理对象的方法
* args:方法的参数
* 返回值:
* Object 方法的返回值

*/


@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
// TODO Auto-generated method stub
System.out.println("调用代理对象方法前记录日志");
method.invoke(obj);
System.out.println("调用代理对象方法后记录日志");
return null;
}


}


书写测试类:

package com.hxkj.jdkproxy;


import java.lang.reflect.Proxy;


import com.hxkj.proxy.Car;
import com.hxkj.proxy.Moveable;


/**
 * 测试动态代理
 * @author wangbin
 *
 */
public class Test {


public static void main(String[] args) {
// TODO Auto-generated method stub
/**
* 创建被代理对象
*/
Car car = new Car();
/**
* 向时间处理器传入被代理对象生成被代理对象的时间处理器对象
*/
TimeHandler timeHandler = new TimeHandler(car);
/**
* 参数:
* loader:被代理对象的类加载器
* interfaces:被代理对象的接口
* h InvocationHandler:代理对象关联的被代理对象的各种(时间,日志。。。。等)处理器
*/
Moveable m=(Moveable) Proxy.newProxyInstance(car.getClass().getClassLoader(), car.getClass().getInterfaces(), timeHandler);
LogHandler logHandler = new LogHandler(m);
Moveable m2=(Moveable) Proxy.newProxyInstance(car.getClass().getClassLoader(), car.getClass().getInterfaces(), logHandler);
m2.move();
}


}

        Proxy类的设计用到代理模式的设计思想,Proxy类对象实现了代理目标的所有接口,并代替目标对象进行实际的操作。但这种替代不是一种简单的替代,这样没有任何意义,代理的目的是在目标对象方法的基础上作增强,这种增强的本质通常就是对目标对象的方法进行拦截。所以,Proxy应该包括一个方法拦截器,来指示当拦截到方法调用时作何种处理。InvocationHandler就是拦截器的接口
  
  总结:随着业务逻辑的不断增多,功能的增加,使用继承方式增加功能会导致类膨胀。

                   代理和继承都是为了拓展业务功能,使用代理实现的话,更加灵活,易于拓展

                    


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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值