设计模式-代理模式

结构型模式

描述将类或者对象按某种布局组成更大的结构。

分为类结构型模式和对象结构型模式。

类结构型模式采用继承机制组织接口和类。

对象结构型模式采用组合或聚合组合对象。

对象结构型模式耦合度低,比类结构型模式具有更大的灵活性。

 模式意图

给某个对象提供一个代理对象,目标对象不适合直接访问,代理对象作为中介。

分为静态代理和动态代理,动态代理又分为JDK动态代理和CGLIB动态代理

结构

  • 抽象目标类
  • 真实目标类:实现具体业务,是代理对象所代表的真实对象
  • 代理类:可以访问、控制或扩展真实目标类的功能

 静态代理

火车站卖票,通过代售点进行取票,火车站是目标对象,代售点是代理对象

 


public class Client {
    public static void main(String[] args) {
        ProxyPoint proxyPoint = new ProxyPoint();
        proxyPoint.sell();
    }
}


interface SellTickets{
    void sell();
}

class TrainStation implements SellTickets{
    @Override
    public void sell() {
        System.out.println("火车站卖票");
    }
}

class ProxyPoint implements SellTickets{
    private TrainStation trainStation = new TrainStation();
    @Override
    public void sell() {
        System.out.println("代理点收取费用");
        trainStation.sell();
    }
}

目标是访问火车站的卖票方法,但是通过代理类间接访问,并且对卖票方法有所加强。

JDK动态代理

动态代理的代理类是程序运行的过程中在内存中动态生成

动态代理对象要代替目标对象执行某个方法

1.首先需要在内存中创建出代理类,所以需要类加载器

2.还需要知道代理对象要执行什么方法,执行的方法是加强过的方法,该方法还得调用目标对象的方法,所以需要获取目标对象所实现的接口执行程序(加强过的方法)。

3.获取动态代理类后,动态代理类中就有了执行程序(加强过的方法)和目标对象的所有方法,动态代理类会把所有方法当作是Method对象存起来

4.动态代理类调用sell方法,就是执行我们写的匿名实现类中的invoke方法,该invoke方法还会执行目标类中的方法(是通过传递method,method是sell,station是执行sell的具体对象,args是该方法的参数)

总结

动态代理类中已经加载好了接口的所有方法的对象,动态代理类的父类加载好了我们写的匿名内部类。

动态代理类调用sell方法,就会调用我们写的匿名内部类中的invoke方法,因为要在invoke方法中再调用目标对象中的sell方法,就把存好的方法对象和所需参数传进来,再由我们自行传入执行该方法的目标类对象,便可实现功能。

package mode;

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

public class Client {
    public static void main(String[] args) {
        //创建代理工厂对象
        ProxyFactory factory = new ProxyFactory();
        //使用factory对象的方法获取代理对象
        SellTickets proxyObject = factory.getProxyObject();
        //调用sell方法,本质是调用invoke方法
        proxyObject.sell();//代售点收取服务费用    火车站卖票

        System.out.println(proxyObject.getClass());
        while (true){

        }
    }
}


interface SellTickets{
    void sell();
}

class TrainStation implements SellTickets{
    @Override
    public void sell() {
        System.out.println("火车站卖票");
    }
}

class ProxyFactory{
    //声明目标对象
    private TrainStation station = new TrainStation();
    public SellTickets getProxyObject(){
        //返回代理对象
        SellTickets proxyObject = (SellTickets) Proxy.newProxyInstance(
                //类加载器,用于加载代理类
                station.getClass().getClassLoader(),
                //代理类实现的接口的字节码对象,能获取里面的方法
                station.getClass().getInterfaces(),
                //代理对象调用的处理程序
                new InvocationHandler() {
                    @Override
                    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                        System.out.println("代售点收取服务费用");
                        //method方法就是sell方法,args是sell方法的参数,返回值就是sell方法的返回值,因为传入的对象是station所以执行的是station方法中的sell方法
                        Object invoke = method.invoke(station, args);
                        return invoke;
                    }
                }
        );
        return proxyObject;
    }
}

通过运行程序,再通过阿里巴巴的阿尔萨斯反编译工具获取到动态代理类,反编译就是将硬件执行的代码转换成高级语言

1.Class.forName获取SellTickets的字节码对象

2.再获取这个类的sell方法,并赋给m3

3.构造器接收参数为invocationHandler,说明创建动态代理对象时必须传递这个参数,这个参数也就是我们自己代码中实现的匿名内部类,构造器中将invocationHandler(调用程序)再传给父类,将这个变量赋值给了父类中的一个成员变量h

 4.执行sell方法就是执行this.h.invoke就是执行匿名内部类中的invoke方法

 CGLIB动态代理

JDK动态代理要求目标类必须实现接口,如果没有接口就不能使用JDK代理了。

CGLIB可以为没有实现接口的类提供代理,为JDK动态动态代理提供了很好的补充。

CGLIB是第三方提供的包,需要引入

三种代理模式的对比

优缺点

优点

 缺点

增加了系统的复杂度

使用场景

 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值