代理模式

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

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

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

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

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

 

posted @ 2019-08-10 22:28  随意的马蒂洛克  阅读(217)  评论(0编辑  收藏  举报