栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

设计模式(5)——代理模式

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

设计模式(5)——代理模式

文章目录
  • 代理模式
    • 静态代理
    • 动态代理
      • JDK
      • 实例讲解
      • CGLib
      • 实例讲解


代理模式

定义:是一种结构型的代理模式。给某一个对象提供一个代理对象,由代理对象控制对原对象的引用。用户可通过远程代理对象来实现对远程原对象的操作。
模式角色:

  • 抽象主题角色:声明了真实主题和代理主题的共同接口,保证了任何使用真实主题的地方都可以使用代理主题。客户端针对抽象主题进行编程。
  • 代理主题角色:内部包含着真实主题对象作为属性成员,用于调用真实主题对象中的操作。不仅如此,还会在此基础上执行一些代理主题独有的操作。
  • 真实主题角色:实现真实的业务操作。

优点:

  1. 保护代理可以控制客户操作权限
  2. 虚拟代理使用小对象代表大对象,减少系统资源的消耗,提升运行速度。

缺点:

  1. 由于在客户端和真实主题之间增加了代理对象,因此有些类型的代理模式可能会造成请求的处理速度变慢。
  2. 实现代理模式需要额外的工作,有些代理模式的实现非常复杂。

代理模式类型:

根据使用目的进行划分

列举常用几种

  • 远程代理,实现本地调用者与远程被调用者之间的正常交互。
  • 虚拟代理,先用小对象来代替资源消耗巨大的对象,真实对象只在需要的时候才被创建。
  • 保护代理,给被调用者提供访问控制,确认调用者的权限。
  • 智能引用代理,代理对象引用真实对象中的操作时,同时包含着一些代理独有的额外的操作。
  • 同步化代理:使得几个用户同时使用一个真实对象不会发生冲突。

根据实现方式进行划分

  • 静态代理
  • 动态代理
静态代理

实例说明:

  1. 保护代理的静态实现

这里演示某一网站注册用户和未注册用户的权限管理。用户必须注册后才能进行一些功能的操作,否则只有查看功能权限。

AbstractPermission

public interface AbstractPermission {
    
    void look();
    
    void comment();
    
    void publish();
    
    void register(boolean flag);
}

RegisteredUser

public class RegisteredUser implements AbstractPermission {
    @Override
    public void look() {
        System.out.println("查看帖子");
    }

    @Override
    public void comment() {
        System.out.println("发出评论");
    }

    @Override
    public void publish() {
        System.out.println("发出帖子");
    }

    @Override
    public void register(boolean flag) {

    }
}

UnRegisteredUser

public class UnRegisteredUser implements AbstractPermission{
    private boolean flag=false;
    private AbstractPermission registerUser=new RegisterUser();
    @Override
    public void look() {
        registerUser.look();
    }

    @Override
    public void comment() {
        if(!flag)
        {
            System.out.println("无账号不能评论,是否立即注册!");
        }else
        {
            registerUser.comment();
        }
    }

    @Override
    public void publish() {
        if(!flag)
        {
            System.out.println("无账号不能发布帖子,是否立即注册!");
        }else
        {
            registerUser.publish();
        }
    }

    @Override
    public void register(boolean flag) {
        this.flag=flag;
    }
}

TestUser

public class TestUser {
    public static void main(String[] args) {
        AbstractPermission user=new UnRegisteredUser();
        user.look();
        user.publish();
        user.comment();
        System.out.println("注册一个账号");
        user.register(true);
        user.look();
        user.publish();
        user.comment();
        
    }
}

动态代理

如果是静态代理的话,真实角色必须事先存在,一个真实主题角色必须对应一个代理主题角色,且真实主题角色作为代理主题角色的内部成员属性,这将导致系统中类的个数急剧增加。所以动态代理解决了事先不知道真实主题角色的情况下,如何使用代理主题角色的问题。

JDK

使用java.lang.reflect包中的类和接口实现动态代理功能

1、 InvocationHander

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

proxy表示目标类
method表示目标类中的目标方法
args表示目标方法中的入参

其中invoke()方法中表示代理对象需要执行的功能代码,包括
(1)执行目标类中的方法
(2)功能增强,在目标方法调用时,增加一些额外的功能

2、 Method

目标类中的方法对象,可通过反射机制获得

Class clazz = A.class;
// 方法名 方法参数类型 
Method method = clazz.getMethod("ok",String.class);

getMethod(String name, Class... parameterTypes)
作用:获取类对象中的某个方法
参数:(1)目标方法名称 (2)目标方法的参数类型,可变长度类型

得到目标方法对象后,执行该目标方法

method.invoke(new A(),"bai");

invoke(Object obj, Object... args)
参数:(1)目标对象 (2)目标方法的参数值,可变长度类型

3、 Proxy

内部提供了 newProxyInstance() 用于创建代理对象

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

loader:目标对象的类的类加载器
interfaces:目标对象的类实现的接口
h:代理对象完成的功能,自行定义

实例讲解

步骤如下

  1. 创建接口,定义抽象方法
  2. 创建目标类,实现接口
  3. 创建InvocationHandler接口的实现类,在invoke方法中实现代理类的功能
    (1)调用目标方法
    (2)增强功能
  4. 使用Proxy获得代理对象
public interface AbstractPermission {
    
    void look();
    
    void comment();
    
    void publish();

}
public class RegisteredUser implements AbstractPermission {
    @Override
    public void look() {
        System.out.println("查看帖子");
    }

    @Override
    public void comment() {
        System.out.println("发出评论");
    }

    @Override
    public void publish() {
        System.out.println("发出帖子");
    }
}
public class ProxyHandler implements InvocationHandler {

    private boolean isRegister = false;

    private Object targetObj;
	
	// 动态传入目标对象
    public ProxyHandler(Object obj){
        this.targetObj = obj;
    }

    public void register(){
        this.isRegister = true;
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {

        if(!isRegister){
            System.out.println("未注册,无权限执行");
            return null;
        }

        return method.invoke(targetObj,args);
    }
}

public class TestUser {

    public static void main(String[] args) {

        // 1、创建目标对象
        AbstractPermission user = new RegisteredUser();

        // 2、InvocationHandler 实现代理对象增强功能
        InvocationHandler h = new ProxyHandler(user);

        // 3、创建代理对象
        AbstractPermission proxyObj = (AbstractPermission)Proxy.newProxyInstance(user.getClass().getClassLoader(),
                                        user.getClass().getInterfaces(),h);

        proxyObj.publish();

        System.out.println("----------------进行注册---------------");

        ((ProxyHandler) h).register();

        proxyObj.publish();

    }
}


思考:如何对目标对象中的不同方法做不同的代理增强?

CGLib

cglib是第三方工具库,创建代理对象

实例讲解

参考书籍:
设计模式.刘伟.胡志刚.郭克华.清华大学出版社

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/345416.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号