代理模式的定义为:为其他对象提供一个代理来控制对它的访问。
英文定义:Provide a surrogate or placeholder for another object to control access to it.
这个中文定义没有很好的反映出原本的意思。英文定义中的surrogate与placeholder都有代理的意思。但是他们之间肯定存在微妙的差别。
以下翻译结果,来自有道
surrogate
- n. 代理;代用品;遗嘱检验法官
- vt. 代理;指定某人为自己的代理人
- adj. 代理的;替代的
placeholder
n. 占位符
我的理解是,surrogate是代理中动的一方面,而placeholder则是静的一面。
代理模式有很多分类:
Remote Proxy
A remote proxy provides a local representative for an object in a difference address space.
Remote proxies are responsible for encoding a request and its arguments and for sending the encoded request to the real subject in a difference address space.
Virtual Proxy
A virtual proxy creates expensive objects on demand.
Virtual proxies may cache additional information about the real subject so that they can postpone accessing it.
Protection Proxy
A protection proxy controls access to the original object.
Protection proxies check that the caller has the access permissions required to perform a request.
Smart Reference
A smart reference is a replacement for a bare pointer that performs additional actions when an object is accessed.
除了以上比较重要的用途外,还有以下类型:
Firewall Proxy
Caching Proxy
Synchronization Proxy
Complexity Hidding Proxy
Copy-On-Write Proxy
可见Proxy的用途是非常广泛的。
Proxy可以与real subject继承自同一基类,这样任何用到proxy的地方,都可已用real subject来代替,
这一点与decorator模式非常相似,但是他们的intent是不同的。
以下例子是利用java提供的Proxy实现的Protection Proxy。
定义subject对应接口
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);
}
public class PersonBeanImpl implements PersonBean {
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 getHotOrNotRating() {
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 setHotOrNotRating(int rating) {
this.rating += rating;
ratingCount++;
}
}
定义proxy的handler
import java.lang.reflect.*;
public class OwnerInvocationHandler implements InvocationHandler {
PersonBean person;
public OwnerInvocationHandler(PersonBean 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("setHotOrNotRating")) {
throw new IllegalAccessException();
} else if (method.getName().startsWith("set")) {
return method.invoke(person, args);
}
} catch (InvocationTargetException e) {
e.printStackTrace();
}
return null;
}
}
import java.lang.reflect.*;
public class NonOwnerInvocationHandler implements InvocationHandler {
PersonBean person;
public NonOwnerInvocationHandler(PersonBean person) {
this.person = person;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
try {
if (method.getName().startsWith("get")) {
return method.invoke(person, args);
} else if (method.getName().equals("setHotOrNotRating")) {
return method.invoke(person, args);
} else if (method.getName().startsWith("set")) {
throw new IllegalAccessException();
}
} catch (InvocationTargetException e) {
e.printStackTrace();
}
return null;
}
}
测试代码
import java.lang.reflect.*;
import java.util.ArrayList;
public class MatchMakingTestDrive {
// instance variables here
ArrayList<PersonBean> persons;
public static void main(String[] args) {
MatchMakingTestDrive test = new MatchMakingTestDrive();
test.drive();
}
public MatchMakingTestDrive() {
initializeDatabase();
}
public void drive() {
PersonBean joe = getPersonFromDatabase("Joe Javabean");
PersonBean ownerProxy = getOwnerProxy(joe);
System.out.println("Name is " + ownerProxy.getName());
ownerProxy.setInterests("bowling, Go");
System.out.println("Interests set from owner proxy");
try {
ownerProxy.setHotOrNotRating(10);
} catch (Exception e) {
System.out.println("Can't set rating from owner proxy");
}
System.out.println("Rating is " + ownerProxy.getHotOrNotRating());
PersonBean nonOwnerProxy = getNonOwnerProxy(joe);
System.out.println("Name is " + nonOwnerProxy.getName());
try {
nonOwnerProxy.setInterests("bowling, Go");
} catch (Exception e) {
System.out.println("Can't set interests from non owner proxy");
}
nonOwnerProxy.setHotOrNotRating(3);
System.out.println("Rating set from non owner proxy");
System.out.println("Rating is " + nonOwnerProxy.getHotOrNotRating());
}
PersonBean getOwnerProxy(PersonBean person) {
return (PersonBean)Proxy.newProxyInstance(
person.getClass().getClassLoader(),
person.getClass().getInterfaces(),
new OwnerInvocationHandler(person));
}
PersonBean getNonOwnerProxy(PersonBean person) {
return (PersonBean)Proxy.newProxyInstance(
person.getClass().getClassLoader(),
person.getClass().getInterfaces(),
new NonOwnerInvocationHandler(person));
}
private void initializeDatabase() {
persons = new ArrayList<PersonBean>();
PersonBean personBean = new PersonBeanImpl();
personBean.setName("Joe Javabean");
personBean.setGender("male");
personBean.setInterests("Drinking");
personBean.setHotOrNotRating(2);
persons.add(personBean);
}
private PersonBean getPersonFromDatabase(String name) {
for (PersonBean person : persons) {
if (person.getName().equals(name)) {
return person;
}
}
return null;
}
}