Java--设计模式之代理模式

本文详细介绍了Java中的静态代理和动态代理概念,通过代码示例展示了如何实现业务的分工与扩展。静态代理用于在不修改真实角色的基础上增加额外功能,但代码量大。动态代理则在运行时动态创建代理类,解决了静态代理的缺点,降低了代码冗余。通过InvocationHandler接口和Proxy类,动态代理能够在运行时灵活处理代理逻辑,如日志记录、权限校验等。
摘要由CSDN通过智能技术生成
静态代理
1、业务分工

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-YlkvAPIT-1607344258660)(C:\Users\admin\AppData\Roaming\Typora\typora-user-images\1607074829487.png)]

从上面这张图,我们可以得出一共有四个角色,分别为:

  • 抽象角色:一般使用接口或者抽象类来实现(买房)

  • 真实角色:被代理的角色(房东)

  • 代理角色:代理真实角色 ; 代理真实角色后 , 一般会做一些附属的操作 .(中介)

  • 客户:使用代理角色来进行一些操作(客户)

2、步骤

接口

真实角色

代理角色

客户端访问

1、接口

//抽象角色
public interface Rent {
    void rent();
}

2、真实角色

// 真实角色(房东)
public class Host implements Rent {
    public void rent() {
        System.out.println("我要出租房子");
    }
}

3、代理角色

//代理角色(中介)
public class HostProxy implements Rent {

    Host host;

    public HostProxy(Host host) {
        this.host = host;
    }

    public void rent() {
        host.rent();
    }

    public void seeHouse() {
        System.out.println("中介带你看房");
    }

    public void fare() {
        System.out.println("收中介费");
    }

    public void heTong() {
        System.out.println("签合同");
    }
}

4、客户端访问

// 客户
public class Cilent {
    public static void main(String[] args) {
        Host host = new Host();
        HostProxy hostProxy = new HostProxy(host);
        hostProxy.seeHouse();
        hostProxy.heTong();
        hostProxy.fare();
        hostProxy.rent();
    }
}

3、代理模式的好处:
  • 可以是真实的角色的操作更加纯粹!不用过多的关注一些公共的业务
  • 公共的业务就交给代理角色!实现了业务的分工
  • 公共业务发生扩展的时候,方便集中管理
4、缺点
  • 一个真实的角色就会产生一个代理角色,代码量会翻一倍,开发效率低
再次理解静态代理

1、接口

//抽象角色
public interface UserService {
    void add();
    void delete();
    void update();
    void query();
}

2、真实角色

// 真实角色
public class UserServiceImpl implements  UserService {
    public void add() {
        System.out.println("增加用户");
    }

    public void delete() {
        System.out.println("删除用户");
    }

    public void update() {
        System.out.println("更新用户");
    }

    public void query() {
        System.out.println("查询用户");
    }
}

3、代理角色

public class UserServiceProxy implements UserService {

    UserServiceImpl userService;

    public void setUserService(UserServiceImpl userService) {
        this.userService = userService;
    }

    public void add() {
        log("add");
        userService.add();
    }

    public void delete() {
        log("delete");
        userService.delete();
    }

    public void update() {
        log("update");
        userService.update();
    }

    public void query() {
        log("query");
        userService.query();
    }

    // 日志方法
    public void log(String msg) {
        System.out.println("使用了"+msg+"方法");
    }
}

4、客户端访问

public class Client {
    public static void main(String[] args) {
        // 真实角色
        UserServiceImpl userService = new UserServiceImpl();

        UserServiceProxy proxy = new UserServiceProxy();
        proxy.setUserService(userService);
        proxy.add();
    }
}

代理模式可以在不修改被代理对象的基础上,通过扩展代理类,进行一些功能的附加与增强。值得注意的是,代理类和被代理类应该共同实现一个接口,或者是共同继承某个类。

动态代理

1、为什么需要?解决静态代理的缺点

2、动态代理的角色和静态代理一样

上一节代码中 HostProxyUserServiceProxy 类是代理,我们需要手动编写代码让HostProxyUserServiceProxy 分别实现 RentUserService接口,而在动态代理中,我们可以让程序在运行的时候自动在内存中创建一个实现 RentUserService 接口的代理,而不需要去定义 HostProxyUserServiceProxy 这两个类。这就是它被称为动态的原因。

1、前提需要了解两个类

InvocationHandler、Proxy

InvocationHandler

1、每个代理的实例都有一个与之关联的 InvocationHandler 实现类,如果代理的方法被调用,那么代理便会通知和转发给内部的 InvocationHandler 实现类,由它决定处理。

2、方法

public interface InvocationHandler {
    public Object invoke(Object proxy, Method method, Object[] args)
        throws Throwable;
}

InvocationHandler 内部只是一个 invoke() 方法,正是这个方法决定了怎么样处理代理传递过来的方法调用。

  • proxy 代理对象
  • method 代理对象调用的方法
  • args 调用的方法中的参数

Proxy

1、 通过 Proxy 的静态方法 newProxyInstance 才会动态创建代理。

2、方法

public static Object newProxyInstance(ClassLoader loader,
                                          Class<?>[] interfaces,
                                          InvocationHandler h)

下面讲解它的 3 个参数意义。

  • loader :自然是类加载器
  • interfaces :代码要用来代理的接口
  • h: 一个 InvocationHandler 对象

返回值:就是创建好的动态代理对象

2、步骤

1、抽象角色

//抽象角色
public interface Rent {
    void rent();
}

2、真实角色

// 真实角色(房东)
public class Host implements Rent {
    public void rent() {
        System.out.println("我要出租房子");
    }
}

3、 代理角色

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

// 代理角色
public class ProxyInvacationHandler implements InvocationHandler {

    // 被代理的接口
    private Rent rent;

    public void setRent(Rent rent) {
        this.rent = rent;
    }

    // 生成得到代理类
    public Object getProxy() {
       return  Proxy.newProxyInstance(this.getClass().getClassLoader(),
               rent.getClass().getInterfaces(),this);
    }

    // 处理代理实例,并返回结果
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        // 动态代理的本质,就是使用反射机制实现
        seeHouse();
        Object result = method.invoke(rent, args);
        fare();
        return  result;
    }


    public void seeHouse() {
        System.out.println("我要看房子");
    }

    public void fare() {
        System.out.println("收中介费");
    }
}

4、客户端

public class Client {
    public static void main(String[] args) {
        // 真实角色
        Host host = new Host();

        // 代理角色:没有
        ProxyInvacationHandler proxyInvacationHandler = new ProxyInvacationHandler();
        // 通过调用程序处理角色来处理我们要调用的接口对象
        proxyInvacationHandler.setRent(host);

        Rent proxy = (Rent) proxyInvacationHandler.getProxy();// 这里的proxy就是动态生成的

        proxy.rent();
    }
}

3、好处
  • 可以是真实的角色的操作更加纯粹!不用过多的关注一些公共的业务
  • 公共的业务就交给代理角色!实现了业务的分工
  • 公共业务发生扩展的时候,方便集中管理
  • 一个动态代理类代理的是一个接口,一般就是对应的一类业务
  • 一个动态代理类可以代理多个类,只要是实现了同一个接口即可
再次理解动态代理

1、抽象角色

//抽象角色
public interface UserService {
    void add();
    void delete();
    void update();
    void query();
}

2、真实角色

// 真实角色
public class UserServiceImpl implements  UserService {
    public void add() {
        System.out.println("增加用户");
    }

    public void delete() {
        System.out.println("删除用户");
    }

    public void update() {
        System.out.println("更新用户");
    }

    public void query() {
        System.out.println("查询用户");
    }
}

3、代理角色

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

// 代理角色
public class ProxyInvacationHandler implements InvocationHandler {


    // 被代理的接口
    private Object object;

    public void setObject(Object object) {
        this.object = object;
    }

    // 生成得到代理类
    public Object getProxy() {
       return  Proxy.newProxyInstance(this.getClass().getClassLoader(),
               object.getClass().getInterfaces(),this);
    }

    // 处理代理实例,并返回结果
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        // 动态代理的本质,就是使用反射机制实现
        log(method.getName());
        Object result = method.invoke(object, args);
        return  result;
    }

    // 增加日志
    public void log(String msg) {
        System.out.println("执行了"+msg+"方法");
    }
}

4、客户端

import com.hui.jingtaidaili.test.UserService;
import com.hui.jingtaidaili.test.UserServiceImpl;

public class Client {
    public static void main(String[] args) {
        UserServiceImpl userService = new UserServiceImpl();

        ProxyInvacationHandler proxyInvacationHandler = new ProxyInvacationHandler();
        proxyInvacationHandler.setObject(userService);
        UserService proxy = (UserService) proxyInvacationHandler.getProxy();

        proxy.add();
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值