代理模式
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的静态方法创建的.
代理模式为客户对象提供一个代理,用来控制客户对对象的访问.
所以代理模式主要是用一个代理类替换目标类的,这里面可以拓展功能,也可以加别的判断设置权限,而不是单纯的通过组合方式拓展功能.
总之,代理模式不只是拓展功能.
(如果只是看博客学习东西的话,我可能还被蒙在鼓里,书上的东西正确多了,而且都是作者经过多年的经验得出的结论,建议大家多看看书,比较准确,看博客容易被误导.)