代理模式

概述

某些情况下,一个客户不想或不能直接引用一个对象,此时可以通过代理对象实现间接引用,通过代理对象去掉客户不能看到的内容和添加客户需要的额外服务


模式实例

在一个论坛已注册用户和游客权限不同,已注册用户拥有发帖、修改注册信息、修改自己帖子等功能;而游客只能看到别人发的贴子,没有其他权限。本实例中我们使用代理模式中的保护代理,该代理用于控制对一个对象的访问,可以给不同用户提供不同级别的使用权限

AbstractPermission(抽象权限类)

public interface AbstractPermission {

   public void modifyUserInfo();

   public void viewNote();

   public void publishNote();

   public void modifyNote();

   public void setLevel(int level);
}

RealPermission(真实权限类)

public class RealPermission implements AbstractPermission {

   @Override
   public void modifyUserInfo() {
       System.out.println("修改用户信息");
   }

   @Override
   public void viewNote() { }
   
   @Override
   public void publishNote() {
       System.out.println("发布新帖");
   }

   @Override
   public void modifyNote() {
       System.out.println("修改发帖内容");
   }

   @Override
   public void setLevel(int level) { }
}

PermissionProxy(权限代理类)

在 PermissionProxy 中定义了一个 RealPermission 对象,用于调用 RealPermission 中定义的真实业务方法,通过引入 PermissionProxy 类来对系统的使用权限进行控制

public class PermissionProxy implements AbstractPermission {

   private RealPermission permission = new RealPermission();
   private int level = 0;

   @Override
   public void modifyUserInfo() {
       if (0 == level) {
           System.out.println("对不起,你没有该权限");
       } else if (1 == level) {
           permission.modifyUserInfo();
       }
   }

   @Override
   public void viewNote() {
       System.out.println("查看帖子");
   }

   @Override
   public void publishNote() {
       if (0 == level) {
           System.out.println("对不起,你没有该权限");
       } else if (1 == level) {
           permission.publishNote();
       }
   }

   @Override
   public void modifyNote() {
       if (0 == level) {
           System.out.println("对不起,你没有该权限");
       } else if (1 == level) {
           permission.modifyNote();
       }
   }

   @Override
   public void setLevel(int level) {
       this.level = level;
   }
}

测试类 Client

public class Client {

   public static void main(String[] args) {

       AbstractPermission permission = new PermissionProxy();

       permission.modifyUserInfo();
       permission.viewNote();
       permission.publishNote();
       permission.modifyNote();

       System.out.println("-------------------------");

       permission.setLevel(1);
       permission.modifyUserInfo();
       permission.viewNote();
       permission.publishNote();
       permission.modifyNote();
   }
}

静态代理

所谓静态代理,就是由程序员创建或特定工具自动生成源代码,也就是在编译时就已经将接口,被代理类,代理类等确定下来。在程序运行之前,代理类的 .class 文件就已经生成,上述的实例就属于静态代理


动态代理

Java 自带的基于接口的动态代理能在运行时根据 Java 代码中的指示动态生成的代理类,其实现相关类位于 java.lang.reflect 包,主要涉及两个类

InvocationHandler 接口:代理对象的关联调用接口,定义了 invoke 方法。当代理对象调用某个方法时,将被调度到关联调用接口的 invoke 方法处理

/**
  *	proxy 表示动态代理类
  *	method 表示需要代理的方法
  *	args 表示代理方法的参数数组
  */
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable;

Proxy 类:该类提供了用于为接口创建代理实例的静态方法

public class Proxy implements java.io.Serializable {

   ...

    /**
     *	根据传入的接口类型返回一个动态创建的代理类实例
     *	loader 表示被代理类的类加载器
     * interfaces 表示被代理类实现的接口列表(与真实主题类的接口列表一致)
     *	h 表示所指派的调用处理程序类
     */
	public static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h) {
       ...
}

现有类 RealSubjectA ,通过 Java 动态代理实现一个代理类

抽象接口 AbstractSubject

public interface AbstractSubject {

    public void request();

}

RealSubjectA

public class RealSubjectA implements AbstractSubject {

    @Override
    public void request() {
        System.out.println("AAA");
    }
}

动态代理类 DynamicProxy

public class DynamicProxy implements InvocationHandler {

    private Object obj;

    public DynamicProxy() {}

    public DynamicProxy(Object obj) {
        this.obj = obj;
    }

    //  实现 invoke() 方法,调用在真实主题类中定义的方法
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {

        System.out.println("调用之前");
        //  利用反射调用方法,如果方法没有返回值则为 null
        Object result = method.invoke(obj, args);
        System.out.println("调用之后");
        return result;
    }
}

测试类 Client

public class Client {

    public static void main(String[] args) {

        AbstractSubject subject = new RealSubjectA();
        InvocationHandler handler = new DynamicProxy(subject);
        AbstractSubject subjectProxy = (AbstractSubject) Proxy.newProxyInstance(subject.getClass().getClassLoader(),
                subject.getClass().getInterfaces(), handler);
        subjectProxy.request();
    }
}
posted @   低吟不作语  阅读(788)  评论(0编辑  收藏  举报
编辑推荐:
· 浏览器原生「磁吸」效果!Anchor Positioning 锚点定位神器解析
· 没有源码,如何修改代码逻辑?
· 一个奇形怪状的面试题:Bean中的CHM要不要加volatile?
· [.NET]调用本地 Deepseek 模型
· 一个费力不讨好的项目,让我损失了近一半的绩效!
阅读排行:
· 没有源码,如何修改代码逻辑?
· PowerShell开发游戏 · 打蜜蜂
· 在鹅厂做java开发是什么体验
· 百万级群聊的设计实践
· WPF到Web的无缝过渡:英雄联盟客户端的OpenSilver迁移实战
点击右上角即可分享
微信分享提示