zoukankan      html  css  js  c++  java
  • 代理模式

    1.定义

    为另一个对象提供一个替身或占位符以访问这个对象.

    以前理解的代理模式有错误,我以为只是把对象组合到另一个对象中就是代理模式,其实不是,代理模式主要是提供一个目标对象访问的代理类,这个代理类可以引用目标类的方法,也可以控制目标类的访问.

    例如动态代理中所有的方法都会走invoke方法,我们可以在这个类中来控制方法的调用.

    2.代码实现

     假设有两种权限,本人登陆的话可以修改个人信息,属性等方法,如果是别人登陆的话只能获取信息,不能修改.

    先设立共同的接口,因为代理模式要求代理类和被代理类实现相同的接口

    package dynamic;
    
    public interface PersonBean {
        String getName();
        String getGender();
        String getInterests();
        int getHotOrNotRating();
        
        void setName(String name);
        void setGender(String gender);
        void setInterests(String interests);
        void setHotOrNotRating(int rating);
    }

    定义接口的实现类

    package dynamic;
    
    public class PersonBeanImpl implements PersonBean {
        String name;
        String gender;
        String interests;
        int rating;
        int ratingCount;
        public String getName() {
            return name;
        }
        public void setName(String name) {
            this.name = name;
        }
        public String getGender() {
            return gender;
        }
        public void setGender(String gender) {
            this.gender = gender;
        }
        public String getInterests() {
            return interests;
        }
        public void setInterests(String interests) {
            this.interests = interests;
        }
        public int getRating() {
            return rating;
        }
        public void setRating(int rating) {
            this.rating = rating;
        }
        public int getRatingCount() {
            return ratingCount;
        }
        public void setRatingCount(int ratingCount) {
            this.ratingCount = ratingCount;
        }
        @Override
        public int getHotOrNotRating() {
            if (ratingCount == 0) return 0;
            return (rating/ratingCount);
        }
        @Override
        public void setHotOrNotRating(int rating) {
            this.rating += rating;
            ratingCount++;
        }
        @Override
        public String toString() {
            return "PersonBeanImpl [name=" + name + ", gender=" + gender + ", interests=" + interests + ", rating=" + rating
                    + ", ratingCount=" + ratingCount + "]";
        }
        
    
    }

    包含get set 方法和一些实现类

    定义自己登陆的代理类,可以使用set方法,如果使用jdk的动态代理的话需要实现 InvocationHandler接口

    package dynamic;
    
    import java.lang.reflect.InvocationHandler;
    import java.lang.reflect.Method;
    
    import dynamic.PersonBean;
    
    public class OwnerInvocationHandler implements InvocationHandler{
        PersonBean personBean;
        
        public OwnerInvocationHandler(PersonBean personBean) {
            this.personBean = personBean;
        }
        
        @Override
        public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
            String methodName = method.getName();
            if (methodName.startsWith("get")) {
                return method.invoke(personBean, args);
            } else if (methodName.startsWith("set")) {
                return method.invoke(personBean, args);
            }
            return null;
        }
    
    }

    这边可以通过Method类的方法 getName获取方法的姓名,通过前缀get和set方法来控制方法的调用,这边set和get方法都可以正常使用.

    定义别人的代理类

    package dynamic;
    
    import java.lang.reflect.InvocationHandler;
    import java.lang.reflect.Method;
    
    public class NonOwnerInvocationHandler implements InvocationHandler{
        PersonBean personBean;
        
        public NonOwnerInvocationHandler(PersonBean personBean) {
            super();
            this.personBean = personBean;
        }
    
        @Override
        public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
            String methodName = method.getName();
            if (methodName.startsWith("get")) {
                return method.invoke(personBean, args);
            } else if (methodName.startsWith("set")) {
                throw new IllegalAccessException();
            }
            return null;
        }
        
        
    }

    set方法抛出异常

    测试类

    package dynamic;
    
    import java.util.Arrays;
    
    public class MatchMakingTestDrive {
        public static void main(String[] args) {
            MatchMakingTestDrive test = new MatchMakingTestDrive();
            test.drive();
        }
    
        public MatchMakingTestDrive() {
        }
        
        public void drive() {
            PersonBean joe = new PersonBeanImpl();
            PersonBean owner = CreateProxy.getOwnerProxy(joe);
            owner.setGender("123");
            System.out.println(joe);
            
            PersonBean nonOwner = CreateProxy.getNonOwnerProxy(joe);
            String gender = nonOwner.getGender();
            nonOwner.setGender("1");
            System.out.println(gender);
            
            
            
        }
    }

    结果

    PersonBeanImpl [name=null, gender=123, interests=null, rating=0, ratingCount=0]
    Exception in thread "main" java.lang.reflect.UndeclaredThrowableException
        at com.sun.proxy.$Proxy0.setGender(Unknown Source)
        at dynamic.MatchMakingTestDrive.drive(MatchMakingTestDrive.java:22)
        at dynamic.MatchMakingTestDrive.main(MatchMakingTestDrive.java:8)
    Caused by: java.lang.IllegalAccessException
        at dynamic.NonOwnerInvocationHandler.invoke(NonOwnerInvocationHandler.java:20)
        ... 3 more

    在NonOwner调用set方法时抛出了异常.

    3.总结

    动态代理之所以成为动态,是因为它是运行时通过调用Proxy的静态方法创建的.

    代理模式为客户对象提供一个代理,用来控制客户对对象的访问.

    所以代理模式主要是用一个代理类替换目标类的,这里面可以拓展功能,也可以加别的判断设置权限,而不是单纯的通过组合方式拓展功能.

    总之,代理模式不只是拓展功能.

    (如果只是看博客学习东西的话,我可能还被蒙在鼓里,书上的东西正确多了,而且都是作者经过多年的经验得出的结论,建议大家多看看书,比较准确,看博客容易被误导.)

  • 相关阅读:
    WPF 关于拖拽打开文件的注意事项
    asp.net core 3.1中对Mongodb BsonDocument的序列化和反序列化支持
    用百度webuploader分片上传大文件
    多线程学习笔记
    web.config数据库连接字符串加密
    Visual Studio 2010 常用快捷方式
    Team Foundation Server 2013 日常使用使用手册(四)分支与合并
    Team Foundation Server 2013 日常使用使用手册(三)上传新工程、创建任务、创建bug、设置预警
    Team Foundation Server 2013 日常使用使用手册(二)修改、签入、撤销、回滚、对比代码变更
    Team Foundation Server 2013 日常使用使用手册(一)-本地连接TFS、查看任务
  • 原文地址:https://www.cnblogs.com/lishuaiqi/p/11333272.html
Copyright © 2011-2022 走看看