java设计模式之代理模式

java设计模式之代理模式

1.定义

1.1什么是代理模式

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

1.2为什么要使用代理模式

说几个场景大家体会一下
1.现在我们有三个关键的业务ABC,现在需要在B前后加一些非关键业务操作。按照正常操作就是将需要增加的业务嵌入B的前后,但是这就改动了原有代码,也有可能失误导致问题,都不希望这样。所以加入非关键业务的操作交给代理类完成,代理类持有B的引用,在自己的方法中增加非关键业务同时调用B的方法。这样就避免了改动原有代码又实现了需求这就是静态代理。所谓动态就是我可能会向C前后插入等。
2.在一个类似微博的网站,用户对像评论的这种东西有不同的权限,比如游客只能看部分且只能看,普通用户能看的更多,管理员可以管理等等。这时候对用户权限的判断交给代理类,代理类也实现所有的方法,自己进行权限拦截。

个人觉得定义算是很抽象的形容,所以就在从生活出发,来透彻的理解代理模式

案例:小明住在一家很好的公寓里,公寓规定了只有早上7点到八点,晚上6点到7点
可以倒垃圾,但是小明早上起不来,下班晚又赶不上倒垃圾的时间。但是呢,不差钱的小明找了个人有偿帮自己倒垃圾。这就是代理模式,小明倒垃圾的行为被代倒垃圾的人完全替代。

1.2什么是静态代理

静态代理是指预先确定了代理与被代理者的关系,例如小明的代到垃圾的人在时间开放前就确定了。那映射到编程领域的话,就是指代理类与被代理类的依赖关系在编译期间就确定了。下面就是小明倒垃圾行为的代码实现:

先来个倒垃圾的接口:

public interface TakeOutGarbage {

    void throwGarbage();
    
}

小明倒垃圾:

public class XiaoMingTakeOutGarbage implements TakeOutGarbage {

    @Override
    public void TakeOutGarbage() {
        System.out.println("小明的十斤垃圾");
    }

}

代到人:这里还为小明做了垃圾分类

public class ProxyTakeOutGarbageA implements TakeOutGarbage {


    TakeOutGarbage takeOutGarbage;

    public ProxyTakeOutGarbageA(TakeOutGarbage takeOutGarbage) {
        this.takeOutGarbage = takeOutGarbage;
    }

    @Override
    public void TakeOutGarbage() {
        takeOutGarbage.TakeOutGarbage();
    }

    public void  sortGarbage()
    {
        System.out.println("垃圾分类");
    }

}

产生代理对象的静态代理工厂类:

public class ProxyFactory {
    public  static  TakeOutGarbage getProxy()
    {
        return new ProxyTakeOutGarbageA(new XiaoMingTakeOutGarbage());
    }
}

测试:

public static void main(String[] args) {
        ProxyFactory.getProxy().TakeOutGarbage();
    }

输出结果:

小明的十斤垃圾
做了垃圾分类

可以看到代到垃圾的人完全替代了小明,好处也比较明显。虽然小明可以自己去,但是通过代理,小明有时间去做别的事情,而且代理人又可以帮助小明把倒垃圾的事做的更好(垃圾分类)

1.3 动态代理

动态代理本质上仍然是代理,情况与上面介绍的完全一样,只是代理与被代理人的关系是动态确定的,例如小明的邻居老王在开放时间之前没有找好代理人,而是在开放之后才找好的,映射到编程领域为这个关系是在运行时确定的。

那既然动态代理没有为我们增强代理方面的任何功能,那我们为什么还要用动态代理呢,静态代理不是挺好的吗?凡是动态确定的东西大概都具有灵活性,强扩展的优势。上面的例子中如果老王也使用静态代理的话,那么就需要再添加两个类。一个是老王倒垃圾类,一个是老王的代倒垃圾人的类,还的在代理静态工厂中添加一个方法。而如果使用动态代理的话,就只需要生成老王倒垃圾类就可以了,全程只需要一个代倒垃圾人的类,因为我们可以住户的垃圾交给这个带到垃圾的人一起处理。

1.3.1 JDK动态代理

这里只介绍一下JDK动态代理

在java的动态代理机制中,有两个重要的类或接口,一个是InvocationHandler接口、另一个则是 Proxy类,这个类和接口是实现我们动态代理所必须用到的。
InvocationHandler接口是给动态代理类实现的,负责处理被代理对象的操作的,而Proxy是用来创建动态代理类实例对象的,因为只有得到了这个对象我们才能调用那些需要代理的方法。

接下来我们看下实例,老王动态找代理人是如何实现的。
1.构建一个老王倒垃圾类

public class LaoWangTakeOutGarbage implements TakeOutGarbage {

    @Override
    public void TakeOutGarbage() {
        System.out.println("老王的八斤垃圾");
    }

}

2.构建一个动态代理类:

public class DynProxyTakeOutGarbage implements InvocationHandler {

    //被代理对象
    private Object target;

    public DynProxyTakeOutGarbage(Object target) {
        this.target = target;
    }


    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        System.out.println("在干嘛:"+method.getName());
        Object result=method.invoke(target,args);
        sortGarbage();
        return result;
    }

    public void  sortGarbage()
    {
        System.out.println("做了垃圾分类");
    }

}

3.修改工厂类:

public class ProxyFactory {

    public static Object getDynProxy(Object target) {
        InvocationHandler handler = new DynProxyTakeOutGarbage(target);
        return Proxy.newProxyInstance(target.getClass().getClassLoader(), target.getClass().getInterfaces(), handler);
    }
}

4.测试类:

public class test {
    public static void main(String[] args) {
       TakeOutGarbage proxy=(TakeOutGarbage) ProxyFactory.getDynProxy(new LaoWangTakeOutGarbage());
       proxy.TakeOutGarbage();
    }
}

·
输出结果:

在干嘛:TakeOutGarbage
老王的八斤垃圾
做了垃圾分类
1.3.2 JDK动态代理实现的原理

首先Jdk的动态代理实现方法是依赖于接口的,首先使用接口来定义好操作的规范。然后通过Proxy类产生的代理对象调用被代理对象的操作,而这个操作又被分发给InvocationHandler接口的 invoke方法具体执行

public Object invoke(Object proxy, Method method, Object[] args) throws Throwable;
1
此方法的参数含义如下
proxy:代表动态代理对象
method:代表正在执行的方法
args:代表当前执行方法传入的实参
返回值:表示当前执行方法的返回值

例如上面老王案例中,我们使用Proxy类的newProxyInstance()方法生成的代理对象proxy去调用了proxy.takeOutGarbage(“老王的八斤垃圾”);操作,那么系统就会将此方法分发给invoke().其中proxy对象的类是系统帮我们动态生产的,其实现了我们的业务接口TakeOutGarbage

2.总结

可能还是有人有疑问,我直接创建实现类对象,调用其方法不香么。当然是可行的,但是对于有些对象创建的开销很大,我们可以使用代理代替,需要的时候在创建它。
我们用的mybatis,spring都有代理模式。像我们的mapper就是对basemapper的代理。在像spring的@tranztional的事务注解。spring就承担代理的角色。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值