定义
这是一种根据访问权限决定客户可否访问对象的代理。比方说,如果你有一个雇员对象,保护代理
允许雇员调用对象上的某些方法,经理还可以多调用一些其它的方法(像setSalary()
),而人力资源处的雇员可以调用对象上的所有方法。
Java
的java.lang.reflect
包中支持代理,利用java.lang.reflect
包可以在运行时动态地创建一个代理类,实现一个或多个接口,并将方法调用转发到你所指定的类。因为实际的代理类是在运行时创建的,我们称之为:动态代理。
我们利用Java
的动态代理创建我们的“保护代理”:
Proxy0
类是由Java
创建的,它实现了完整的Subject
接口;
- 我们使用
XXXInvocationHandler
来告诉Proxy0
类你要代理的行为,它实现了接口InvocationHandler
中的invoke()
方法,Proxy0
实现的Subject
接口的方法全部被转发给XXXInvocationHandler.invoke()
;
场景
约会服务系统
场景描述
该约会服务系统的要求:
- 允许设置和获取一个人的信息;
- 不允许用户篡改别人的数据;
- 具有评鉴功能,“Hot”表示喜欢对方,“Not”表示不喜欢。
实现方案
服务系统涉及到一个Person
接口,允许设置和获取一个人的信息:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47
| public interface Person { String getName(); String getGender(); String getInterests(); int getGeekRating();
void setName(String name); void setGender(String gender); void setInterests(String interests); void setGeekRating(int rating); }
public class PersonImpl implements Person { String name; String gender; String interests; int rating; int ratingCount = 0;
public String getName() { return name; } public String getGender() { return gender; } public String getInterests() { return interests; } public int getGeekRating() { if (ratingCount == 0) return 0; return (rating / ratingCount); }
public void setName(String name) { this.name = name; } public void setGender(String gender) { this.gender = gender; } public void setInterests(String interests) { this.interests = interests; } public void setGeekRating(int rating) { this.rating += rating; ratingCount++; } }
|
创建两个InvocationHandler
类,invoke()
中实现具体的代理行为;其中,OwnerInvocationHandler
给拥有者使用,NonOwnerInvocationHandler
给非拥有者使用。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53
| import java.lang.reflect.InvocationHandler; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method;
public class OwnerInvocationHandler implements InvocationHandler { Person person;
public OwnerInvocationHandler(Person person) { this.person = person; }
public Object invoke(Object proxy, Method method, Object[] args) throws IllegalAccessException {
try { if (method.getName().startsWith("get")) { return method.invoke(person, args); } else if (method.getName().equals("setGeekRating")) { throw new IllegalAccessException(); } else if (method.getName().startsWith("set")) { return method.invoke(person, args); } } catch (InvocationTargetException e) { e.printStackTrace(); } return null; } }
public class NonOwnerInvocationHandler implements InvocationHandler { Person person;
public NonOwnerInvocationHandler(Person person) { this.person = person; }
public Object invoke(Object proxy, Method method, Object[] args) throws IllegalAccessException {
try { if (method.getName().startsWith("get")) { return method.invoke(person, args); } else if (method.getName().equals("setGeekRating")) { return method.invoke(person, args); } else if (method.getName().startsWith("set")) { throw new IllegalAccessException(); } } catch (InvocationTargetException e) { e.printStackTrace(); } return null; } }
|
实例化Proxy
对象:
1 2 3 4 5 6 7 8 9 10 11 12 13
| Person getOwnerProxy(Person person) { return (Person) Proxy.newProxyInstance( person.getClass().getClassLoader(), person.getClass().getInterfaces(), new OwnerInvocationHandler(person)); }
Person getNonOwnerProxy(Person person) { return (Person) Proxy.newProxyInstance( person.getClass().getClassLoader(), person.getClass().getInterfaces(), new NonOwnerInvocationHandler(person)); }
|
参考
- https://wickedlysmart.com/head-first-design-patterns/