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的静态方法创建的.

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

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

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

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

  • 相关阅读:
    shell脚本按当前日期输出日志
    bat弹出确认或取消窗口
    bat脚本输出日志
    北京浩赢科技有限公司与好宝多多
    bat延迟执行脚本,利用choice实现定时执行功能
    centos下安装tunctl
    OpenStack Train版 简单部署流程(4)- octavia
    LVM基础
    OpenStack Train版 简单部署流程(3)- ceilometer
    openstack stein
  • 原文地址:https://www.cnblogs.com/lishuaiqi/p/11333272.html
Copyright © 2011-2022 走看看