前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >浅谈几种设计模式--代理模式

浅谈几种设计模式--代理模式

作者头像
田维常
发布2019-07-16 10:36:24
6610
发布2019-07-16 10:36:24
举报

代理

代理模式(Proxy Pattern),为其他对象提供一个代理,并由代理对象控制原有对象的引用;也称为委托模式。

1.静态代理

2.动态代理

3.cglib代理:如果目标对象没有实现接口,用Cglib代理

静态代理总结:

1.可以做到在不修改目标对象的功能前提下,对目标功能扩展.

2.缺点:

因为代理对象需要与目标对象实现一样的接口,所以会有很多代理类,类太多.同时,一旦接口增加方法,目标对象与代理对象都要维护。

如何解决静态代理中的缺点呢?

答案是可以使用动态代理方式

spring的Proxy模式在aop中有体现,比如JdkDynamicAopProxy和Cglib2AopProxy。

静态代理

代码语言:javascript
复制
/**
 * 创建Person接口
 */
public interface Person {
        void giveMoney();//上交班费
}
/**
 * Student类实现Person接口。Student可以具体实施上交班费的动作
 */
public class Student implements Person {
    private String name;
    public Student(String name) {
        this.name = name;
    }
    @Override
    public void giveMoney() {
       System.out.println(name + "上交班费50元");
    }
}
代码语言:javascript
复制
/**
 * 学生代理类,也实现了Person接口,保存一个学生实体,这样既可以代理学生产生行为
 */
public class StudentsProxy implements Person{
    //被代理的学生
    Student stu;
    public StudentsProxy(Person stu) {
        // 只代理学生对象
        if(stu.getClass() == Student.class) {
            this.stu = (Student)stu;
        }
    }
    //代理上交班费,调用被代理学生的上交班费行为
    public void giveMoney() {
        stu.giveMoney();
    }
}
代码语言:javascript
复制
/**
 * 测试类
 */
public class StaticProxyTest {
    public static void main(String[] args) {
        //被代理的学生张三,他的班费上交有代理对象monitor(班长)完成
        Person zhangsan = new Student("张三");
        
        //生成代理对象,并将张三传给代理对象
        Person monitor = new StudentsProxy(zhangsan);
      
        //班长代理上交班费
        monitor.giveMoney();
    }
}
代码语言:javascript
复制
/**
 * 学生代理类
 */
public class StudentsProxy implements Person{
    //被代理的学生
    Student stu;
    public StudentsProxy(Person stu) {
        // 只代理学生对象
        if(stu.getClass() == Student.class) {
            this.stu = (Student)stu;
        }
    }
    //代理上交班费,调用被代理学生的上交班费行为
    public void giveMoney() {
        System.out.println("张三最近学习有进步!");
        stu.giveMoney();
    }
}

可以看到,只需要在代理类中帮张三上交班费之前,执行其他操作(方法)就可以了。

这种操作,也是使用代理模式的一个很大的优点。最直白的就是在Spring中的面向切面编程(AOP),我们能在一个切点之前执行一些操作,在一个切点之后执行一些操作,这个切点就是一个个方法。

这些方法所在类肯定就是被代理了,在代理过程中切入了一些其他操作。

动态代理

代码语言:javascript
复制
public void giveMoney() {
        beforeMethod();//调用被代理方法前加入处理方法
        stu.giveMoney();
}
/**
 * 创建Person接口
 */
public interface Person {
     void giveMoney(); //上交班费
}
代码语言:javascript
复制
public class Student implements Person {
    private String name;
    public Student(String name) {
        this.name = name;
    }
    
    @Override
    public void giveMoney() {
        try {
          //假设数钱花了一秒时间
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
       System.out.println(name + "上交班费50元");
    }
}
代码语言:javascript
复制
public class MonitorUtil {
    
    private static ThreadLocal<Long> tl = new ThreadLocal<>();
    
    public static void start() {
        tl.set(System.currentTimeMillis());
    }
    
    //结束时打印耗时
    public static void finish(String methodName) {
        long finishTime = System.currentTimeMillis();
        System.out.println(methodName + "方法耗时" + (finishTime - tl.get()) + "ms");
    }
}
代码语言:javascript
复制
public class StuInvocationHandler<T> implements InvocationHandler {
    T target; //invocationHandler持有的被代理对象
    public StuInvocationHandler(T target) {
       this.target = target;
    }
    /**
     * proxy:代表动态代理对象     method:代表正在执行的方法 args:代表调用目标方法时传入的实参
     */
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        System.out.println("代理执行" +method.getName() + "方法");
        //代理过程中插入监测方法,计算该方法耗时
        MonitorUtil.start();
        Object result = method.invoke(target, args);
        MonitorUtil.finish(method.getName());
        return result;
    }
}

测试类

代码语言:javascript
复制
public class ProxyTest {
    public static void main(String[] args) {

        //创建一个实例对象,这个对象是被代理的对象
        Person zhangsan = new Student("张三");

       //创建一个与代理对象相关联的InvocationHandler
        InvocationHandler stuHandler = new StuInvocationHandler<Person>(zhangsan);
        
        //创建一个代理对象stuProxy来代理zhangsan,代理对象的每个执行方法都会替换执行Invocation中的invoke方法
        Person stuProxy = (Person) Proxy.newProxyInstance(Person.class.getClassLoader(), new Class<?>[]{Person.class}, stuHandler);

       //代理执行上交班费的方法
        stuProxy.giveMoney();
    }
}

总结一下: 上面的动态代理的例子,其实就是AOP的一个简单实现了,在目标对象的方法执行之前和执行之后进行了处理,对方法耗时统计。Spring的AOP实现其实也是用了Proxy和InvocationHandler这两个东西的。

本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2019-05-25,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 Java后端技术栈 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 代理
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档