设计模式(二)代理模式

目录

一、代理模式

二、代理模式角色介绍

三、代理模式结构图

四、代理模式实现

1.静态代理模式

2.动态代理模式 


一、代理模式

        代理模式的定义:为其他对象提供一种代理以控制对这个对象的访问。在某些情况下,一个对象不适合或者不能直接引用另一个对象,而代理对象可以在客户端和目标对象之间起到中介的作用。

二、代理模式角色介绍

  • 抽象角色:通过接口或抽象类声明真实角色实现的业务方法。

  • 代理角色:代理角色:实现抽象角色,是真实角色的代理,通过真实角色的业务逻辑方法来实现抽象方法,并可以附加自己的操作。

  • 真实角色:实现抽象角色,定义真实角色所要实现的业务逻辑,供代理角色调用。

        想象这样一个场景:你来到北京,你需要租房,但因为你不熟悉这边的环境,所以你想请一名中介帮你找房子。这个例子我们可以看到两种角色,真实角色,代理角色。但又是如何将这两类角色联系起来的呢,在这个例子中,买房是真实角色(我)的业务,这里我们将真实角色的业务方法叫做抽象角色。代理模式的关键在于代理角色实现真实角色的业务,基于这个例子的逻辑就是我(真实角色)买房(抽象角色),但因为环境不熟悉,我寻找了中介(代理角色)去买房(抽象角色)。

        为了建立真实角色和代理角色的联系,我们应该解决的其实是怎么让代理角色去执行真实角色的业务,解决方法可以通过接口或者抽象的方式来实现,在接下来我们只通过接口的方式来实现代理模式。

三、代理模式结构图 


四、代理模式实现

        代理模式分为静态代理、动态代理。静态代理是由程序员创建或工具生成代理类的源码,再编译代理类。所谓静态也就是在程序运行前就已经存在代理类的字节码文件,代理类和委托类的关系在运行前就确定了。而动态代理是在实现阶段不用关心代理类,而在运行阶段才指定哪一个对象。

1. 静态代理模式

// 真实角色
public class OrderServiceImpl implements OrderService {
    @Override
    public void show() {
        System.out.println("展示订单详情");
    }

    @Override
    public void generate() {
        System.out.println("订单已生成");
    }

    @Override
    public void delete() {
        System.out.println("删除订单");
    }

    @Override
    public int getRows() {
        System.out.println("获取总订单条目");
        return 100;
    }
}

 
// 抽象角色
public interface OrderService {
    void show();
    void generate();
    void delete();
    int getRows();
}

// 代理角色
public class ProxyOrderServiceImpl implements OrderService {
    private OrderService target;

    public ProxyOrderServiceImpl(OrderService target) {
        this.target = target;
    }

    @Override
    public void show() {
        System.out.println("查找订单中");
        target.show();
    }

    @Override
    public void generate() {
        System.out.println("订单生成中,请稍等...");
        target.generate();
    }

    @Override
    public void delete() {
        target.delete();
    }

    @Override
    public int getRows() {
        System.out.println("统计订单数目");
        return 100;
    }
}

// 客户端
public class StaticProxyClient {
    public static void main(String[] args) {
        OrderService orderServiceImpl = new OrderServiceImpl();
        ProxyOrderServiceImpl proxyOrderService = new          
                 ProxyOrderServiceImpl(orderServiceImpl);
        proxyOrderService.show();
        proxyOrderService.generate();
    }
}

 运行结果:

静态代理模式实现对实际对象的访问控制,提高了系统的安全性,此外通过静态代理实现了原始代码与额外逻辑的分离,没有违背OCP原则。然而这种模式的缺点也很明显,实现代理需要建立实际对象和代理对象一对一的关系,如果有大量的实际对象,那么需要创建多个代理对象,显然这会造成大量类的管理,导致代码的冗余。为了解决这个问题,引出动态代理模式。

2. 动态代理模式

// 真实角色
public class OrderServiceImpl implements OrderService {
    @Override
    public void show() {
        System.out.println("展示订单详情");
    }

    @Override
    public void generate() {
        System.out.println("订单已生成");
    }

    @Override
    public void delete() {
        System.out.println("删除订单");
    }

    @Override
    public int getRows() {
        System.out.println("获取总订单条目");
        return 100;
    }
}

// 抽象角色
public interface OrderService {
    void show();
    void generate();
    void delete();
    int getRows();
}

// 处理器
public class TimeInvocationHandler implements InvocationHandler {
    private Object target;

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

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        System.out.println("invoke");
        Object obj = method.invoke(target, args);
        return obj;
    }
}

// 客户端
public class Client {
    public static void main(String[] args) {
        // 创建目标角色
        OrderService target = new OrderServiceImpl();
        // 创建代理角色
        OrderService proxyObject =             
            (OrderService)Proxy.newProxyInstance(target.getClass().getClassLoader(), 
            target.getClass().getInterfaces(), new TimeInvocationHandler(target));
        // 调用代理对象的代理方法
        proxyObject.show();
        int rows = (int)proxyObject.getRows();
        System.out.println(rows);
    }
}

         之前我们说如果有大量实际角色的话,通过静态代理的方式需要创建大量的代理角色,这造成了代码的冗余。动态代理模式的出现很好地解决了这个问题。那么我们带着这个问题分析这种模式是如何实现的。

        从代码实现来看,是没有设计代理类的。那么是如何创建代理角色的呢,在client类中调用newProxyInstance方法,这是JDK内置的动态代理创建代理对象的方法,这个方法有三个参数,第一个参数是类加载器,第二个参数是Class<?>[] interfaces,第三个参数实现处理器接口的对象。首先我们先清楚,动态代理是在运行时动态获取代理角色,它不同于静态代理的死编码。接下来分析如何写这个方法的参数,这个方法的第一个参数是实际角色的类加载器,这个很好理解,因为我们要拿到代理角色,所以需要告诉内存谁需要被加载,加载的类其实就是真实角色。真实角色和代理角色实现共同的接口,在内存中生成代理类的时候,需要告诉代理类需要实现哪些接口,因而第二个参数就是需要让代理类实现的接口,参数是通过真实对象使用反射技术获取到的。通过这两个参数,我们其实已经可以创建一个代理类对象。

        如果我们需要添加业务逻辑来增强代码,第三个参数的作用就显现了InvocationHandler 是 Java 反射包中的一个接口,用来在实现 JDK 动态代理时提供动态执行增强逻辑的方法。在使用 JDK 动态代理时,需要创建一个 InvocationHandler 的实现类,并实现其中的 invoke() 方法。invoke() 方法会在目标对象的方法被调用时自动被调用,从而可以在目标对象的方法执行前后添加一些自定义的逻辑。

使用 InvocationHandler 需要注意以下几点:
        1. InvocationHandler 不能直接对目标对象进行操作,而是通过 Method 对象来调用目标对象的方法。
        2. InvocationHandler 中的 invoke() 方法需要返回一个与目标对象方法的返回值类型相同的返回值。

        3. 在使用 JDK 动态代理时,必须为每一个需要代理的接口都创建一个对应的 InvocationHandler 实现类。

运行结果:


         上述内容如果有错误的地方,希望大佬们可以指正。我一直在学习的路上,您的帮助使我收获更大!觉得对您有帮助的话,还请点赞支持!我也会不断更新文章!

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

弘弘弘弘~

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值