专题——常见的设计模式(代理模式)

代理模式

由于某些原因需要给某对象提供一个代理以控制对该对象的访问,这时,访问对象不适合或直接引用目标对象,代理对象作为访问对象和目标对象的中介

角色

  • 抽象主题:通过接口或抽象类声明真实主题和代理对象实现的业务方法
  • 真实主题:实现了抽象主题的具体业务,是代理对象所代表的真实对象,是最终要引用的对象
  • 代理类:通过了与真实主题相同的接口,其内部还有对真实主题的引用,它可以访问,控制或扩展真实主题的功能

UML类图

在这里插入图片描述

静态代理

代理类在编译器就生成

抽象主题

// 售票接口
public interface SellTickets {
    void sell();
}

真实主题

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

代理类

// 代理点
public class Agency implements SellTickets {

    // 真实主题的引用
    private Station station = new Station();

    @Override
    public void sell() {
        System.out.println("代理点收取一定费用");
        station.sell();
    }
}

测试类:

public class ProxyClient {

    public static void main(String[] args) {
        // 获取静态代理类
        ProxySell proxySell = new ProxySell();
        // 执行代理方法
        proxySell.sell();
    }
}

执行结果
在这里插入图片描述

动态代理

代理类在java运行时动态生成(分为JDK代理和Cglib代理两种)

JDK代理

抽象主题和真实主题与静态代理类的相同

// 通过代理对象工场生成代理对象
public class ProxyFactory {

    // 声明目标对象
    private Station station = new Station();

    public SellTickets getProxyObject(){

        /**
         * ClassLoader loader, 类加载器,用于加载代理类,可以通过目标对象获取类加载器
         * Class[] interfaces, 代理类实现接口的字节码对象
         * InvocationHandler h 代理对象的调用处理程序
         */
        SellTickets proxyObject = (SellTickets) Proxy.newProxyInstance(station.getClass().getClassLoader(), 
                station.getClass().getInterfaces(), (o, method, objects) -> {
                        System.out.println("invoke方法执行了");
                        System.out.println("代售点收取了一些费用(JDK代理)");
                    Object invoke = method.invoke(station, objects);
                    return invoke;
                });
        return proxyObject;
    }
}

测试类:

public class ProxyClient {

    public static void main(String[] args) {
    	// 创建代理对象工厂
        ProxyFactory proxyFactory = new ProxyFactory();
        // 创建代理对象
        SellTickets proxyObject = proxyFactory.getProxyObject();
        // 调用代理方法
        proxyObject.sell();
    }
}

执行结果:
在这里插入图片描述

Cglib代理

引入依赖
maven:

<dependency>
    <groupId>cglib</groupId>
    <artifactId>cglib</artifactId>
    <version>2.2.2</version>
</dependency>

gradle:

compile group:'cglib',name:'cglib',version:'2.2.2'
真实主题
public class Shop {
    public void sale() {
        System.out.println("商店卖东西");
    }
}
代理类
public class ShopProxyFactory implements MethodInterceptor {

    private Shop shop;

    public ShopProxyFactory(Shop shop) {
        this.shop = shop;
    }

    public Shop getShopProxy() {
        // 创建enhancer对象,相当于jdk代理中的proxy对象
        Enhancer enhancer = new Enhancer();
        // 设置父类字节码,因为使用cglib创建的代理对象实际是被代理对象的子类
        enhancer.setSuperclass(Shop.class);
        // 设置回调函数,传参是Callback  只需要类本身实现MethodInterceptor这个接口,就把这个类进行传参即可
        enhancer.setCallback(this);
        // 创建代理对象
        Shop shop = (Shop) enhancer.create();
        return shop;
    }

    @Override
    public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
        System.out.println("代售点中方法执行了");
        System.out.println("代售点收取了一些费用(cglib)");
        Object invoke = method.invoke(shop, objects);
        return invoke;
    }
}

测试类:

public class ShopProxyClient {
    public static void main(String[] args) {
        ShopProxyFactory shopProxyFactory = new ShopProxyFactory(new Shop());
        Shop shopProxy = shopProxyFactory.getShopProxy();
        shopProxy.sale();
    }
}

执行结果:
在这里插入图片描述

静态代理和动态代理的区别

静态代理在一开始就将代理类生成好了,动态代理在运行时候才会生成
动态代理不用和被代理对象实现同样的接口
静态代理只能通过手动完成代理操作,如果被代理类添加了方法,那么代理类也要添加代理方法,违背开闭原则
动态代理在运行时动态生成代码的方式,取消了被代理类的扩展限制,符合开闭原则

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值