每天学点设计模式---代理模式

代理模式的定义

为其他对象提供一种代理,以控制对这个对象的访问;
代理对象起到中介的作用,可去掉功能服务或者增加额外的服务;
比如:买火车票,可以去火车票代售处购买而不用非得去到火车站,火车票代售处就是火车站的代理,
火车票代售处和火车站的功能的比较:

功能服务 火车站 火车票代售处
火车票的销售功能
提供额外的服务(电话预约) 没有
提供额外的服务(收取手续费) 没有
提供退票服务 没有

火车票代售处就是火车站的代理,可去掉功能服务或者增加额外的服务;

代理模式两种静态代理和动态代理

静态代理

静态代理概念和模型
比如一辆汽车有行驶功能,现在要代理一下汽车行驶,额外增加时间记录功能;
1,相同接口或抽象类

public interface Moveable {

    void move();//公共的行驶

}

//原始的小汽车 实现了Moveable

public class Car implements Moveable {

    @Override
    public void move() {
        System.out.println("汽车行驶过程中。。。。。");
    }

}
通过继承来实现代理

现在的代理小汽车实现了 Moveable (Car本身也是实现了Moveable)

//通过继承的方式来实现代理
public class CarProxy1 extends Car {
    
    @Override
    public void move() {
        System.out.println("汽车开始时间。。。。。");//额外增加时间统计
        super.move();
        System.out.println("汽车结束时间。。。。。");
    }
}
通过聚合来实现代理

现在的代理小汽车实现了 Moveable

public class CarProxy2 implements Moveable {

    public Moveable m;

    public CarProxy2(Car m) {
        this.m = m;
    }

    @Override
    public void move() {

        System.out.println("汽车开始时间。。。。。");//额外增加时间统计
        m.move();
        System.out.println("汽车结束时间。。。。。");

    }

}

继承的方式相比于聚合来讲不灵活;
现在我们添加一个代理日志打印的功能;使用继承的方式会增加下面四中代理类,每个代理类的都是特定的功能如下;
1,统计时间的代理类;
2,统计日志的代理类;
3,先统计时间后统计日志的代理类;
4,先统计日志后统计时间的代理类;
如果使用组合的话,只需要两个类就可以了;看代码
1,统计时间代理类

//代理时间打印的代理
public class CarTimeProxy implements Moveable {

    public Moveable m;

    public CarTimeProxy(Moveable m) {
        this.m = m;
    }

    @Override
    public void move() {

        System.out.println("汽车开始时间。。。。。");//额外增加时间统计
        m.move();
        System.out.println("汽车结束时间。。。。。");

    }

}

统计时间代理类

        Car car = new Car();
        CarTimeProxy carTimeProxy = new CarTimeProxy(car);
        carTimeProxy.move();

2,统计日志代理类

//代理日志打印功能的代理
public class CarLogProxy implements Moveable {

    public Moveable m;

    public CarLogProxy(Moveable m) {
        this.m = m;
    }

    @Override
    public void move() {

        System.out.println("汽车开始日志。。。。。");//额外增加日志打印统计
        m.move();
        System.out.println("汽车结束日志。。。。。");

    }

}

统计日志打印代理类

        Car car = new Car();
        CarLogProxy carLogProxy = new CarLogProxy(car);
        carLogProxy.move();

3,先统计时间后统计日志的代理

        Car car = new Car();
        CarTimeProxy carTimeProxy = new CarTimeProxy(car);
        CarLogProxy carLogProxy = new CarLogProxy(carTimeProxy);
        carLogProxy.move();

4,先统计日志后统计时间的代理

        Car car = new Car();
        CarLogProxy carLogProxy = new CarLogProxy(car);
        CarTimeProxy carTimeProxy = new CarTimeProxy(carLogProxy);
        carTimeProxy.move();

从上面看使用组合方式只需要使用2个类就ok了;

动态代理

上面的小汽车需要做时间上的代理,那么自行车,火车,也需要时间上的代理,其它失误也需要时间上的代理,如下图所示,有一百个事物就需要做100个事物对象的时间代理;
时间代理
那样会造成代理类膨胀;那么有没有一种方式 实现对不同类,不同方法的代理这产生里动态代理,
上面的事例中不同的想要代理时间的对象都是动态产生,这就属于动态代理;

动态代理就是在代理对象和被代理对象之间添加了一个事物处理器;如下图代理的关键两个类:
Proxy:
InVocationHandler:
动态代理的概念和模型
动态代理
具体代码实现:

        //这个Car类,现在要对它做一个时间代理(使用动态代理)
        final Car car = new Car();
        //实现一个InvocationHandler接口
        InvocationHandler invocationHandler = new InvocationHandler() {

            /**
             * @param proxy  代理类Proxy,它是JDK内部的类
             * @param method 被代理类的方法
             * @param args   被代理类方法的参数
             * @return 被代理类的方法返回值
             * @throws Throwable
             */
            @Override
            public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                System.out.println("汽车行驶开始时间。。。。。");
                method.invoke(car, args);
                System.out.println("汽车行驶结束时间。。。。。");
                return null;
            }
        };

        ClassLoader classLoader = Car.class.getClassLoader();
        Class<?>[] interfaces = Car.class.getInterfaces();
        //产生一个代理对象
        final Moveable m = (Moveable) Proxy.newProxyInstance(classLoader, interfaces, invocationHandler);
        //调用方法,就会调用InvocationHandler的invoke方法,整个代理过程都在这个方法里面执行
        m.move();

总结动态代理:这个鬼东西真的很玄幻啊,我刚开始是很晕晕的,
使用一个伪代码解释一下,

public class CarProxy implements Moveable{
    
    InvocationHandler invocationHandler;
    @Override
    public void move() {
        invocationHandler.invoke()
    }
    
}

1,Proxy.newProxyInstance生成的代理类class是在运行时生成,
Proxy.newProxyInstance()生成的就是一个类似上面的代理类CarProxy,里面含有InvocationHandler属性

2,Proxy.newProxyInstance生成的代理类class需要实现一组接口
这里这个代理类CarProxy也是实现了Moveable接口

3,必须实现InvocationHandler,具体代理类业务是在invoke方法里面实现;

当代理类CarProxy调用自己的方法比如move()时候,相当于这个时候InvocationHandler调用自己的invoke方法来执行的;

发布了92 篇原创文章 · 获赞 68 · 访问量 19万+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章