代理模式是一种行为型模式,这个模式的意图是为其他对象提供一种代理以控制对原始对象的访问。为何需要代理?因为有时候直接访问原始对象会带来问题,比如,要访问的对象在远程的机器上,或者某些操作需要安全控制。
比如下面这个Document类,它的访问没有任何安全控制,谁都可以执行它的view和edit方法,在现实中这是不合理的,应当对文档加入访问权限的控制。
零、UML类图
一、静态代理
public class Document {
public void view() {
System.out.println("执行查看操作");
}
public void edit() {
System.out.println("执行编辑操作");
}
}
public class Client {
public static void main(String[] args) {
Document doc = new Document();
doc.view();
doc.edit();
}
}
因此,要根据Document向外暴露的方法做一个具有相同方法的代理类。具体做法是,把Document的方法抽取出来形成一个接口。
// 被代理类
public class Document implements Operation {
private String docName;
public Document(String docName) {
this.docName = docName;
}
public void view() {
System.out.println("执行查看操作");
}
public void edit() {
System.out.println("执行编辑操作");
}
}
// 代理类
public class ProxyDocument implements Operation {
private String userName;
private Document realDoc;
public ProxyDocument(String userName) {
this.userName = userName;
}
public void view() {
if (getRoleByName(userName).equalsIgnoreCase("admin") || getRoleByName(userName).equalsIgnoreCase("user")) {
realDoc = new Document("报名表");
// 被代理的对象
realDoc.view();
} else {
System.out.println("只有管理员和注册用户才可以查看");
}
}
public void edit() {
if (getRoleByName(userName).equalsIgnoreCase("admin")) {
realDoc = new Document("报名表");
// 被代理的对象
realDoc.edit();
} else {
System.out.println("只有管理员才可以编辑");
}
}
public String getRoleByName(String userName) {
if ("Tom".equalsIgnoreCase(userName))
return "admin";
else if ("Joe".equalsIgnoreCase(userName))
return "user";
else return "visitor";
}
}
// 共同的接口
public interface Operation {
void view();
void edit();
}
// 客户类
public class Client {
public static void main(String[] args) {
Operation operationsPerformed = new ProxyDocument("tom");
operationsPerformed.view();
operationsPerformed.edit();
}
}
缺点:只能代理某一种类型,要想代理其他类型,需要修改代码。
解决:动态代理。
二、动态代理
public class DynamicProxy implements InvocationHandler {
private Object bean;
public DynamicProxy(Object bean) {
this.bean = bean;
}
public Object invoke(Object o, Method method, Object[] args) throws Throwable {
String methodName = method.getName();
if ("view".equalsIgnoreCase(methodName)) {
System.out.println("欢迎访问");
} else if ("edit".equalsIgnoreCase(methodName)) {
System.out.println("需要编辑,请用管理员用户登录");
}
return method.invoke(bean, args);
}
}
public class DynamicClient {
public static void main(String[] args) {
DynamicProxy proxy = new DynamicProxy(new Document("学生报名表"));
Operation doc = (Operation) Proxy.newProxyInstance(proxy.getClass().getClassLoader(), new Class[]{Operation.class}, proxy);
doc.edit();
DynamicProxy proxy2 = new DynamicProxy(new Document("学生成绩表表"));
Operation doc2 = (Operation) Proxy.newProxyInstance(proxy.getClass().getClassLoader(), new Class[]{Operation.class}, proxy2);
doc2.view();
}
}
常见的代理
- 远程代理。
- 虚拟代理。
- Copy-on-Write 代理。
- 保护(Protect or Access)代理。
- Cache代理。
- 防火墙(Firewall)代理。
- 同步化(Synchronization)代理。
- 智能引用(Smart Reference)代理。
三、参考
- https://www.runoob.com/design-pattern/proxy-pattern.html
- https://blog.csdn.net/u010425839/article/details/107029740
- https://segmentfault.com/a/1190000040680716
- https://www.runoob.com/design-pattern/proxy-pattern.html
- https://www.w3schools.blog/java-proxy-design-pattern
设计模式系列博文导航
一、创建型 - 5种
原型模式(Prototype Pattern)
抽象工厂模式(Abstract Factory Pattern)
建造者模式(Builder Pattern)
工厂模式(Factory Pattern)
单例模式(Singleton Pattern)
助记语:原抽建工单
二、结构型 - 8种
享元模式(Flyweight Pattern)
代理模式(Proxy Pattern)
适配器模式(Adapter Pattern)
外观模式(Facade Pattern)
过滤器模式(Filter/Criteria Pattern)
桥接模式(Bridge Pattern)
组合模式(Composite Pattern)
装饰器模式(Decorator Pattern)
助记语:想呆室外,过桥组装
三、行为型 - 11种
责任链模式(Chain of Responsibility Pattern)
命令模式(Command Pattern)
解释器模式(Interpreter Pattern)
中介者模式(Mediator Pattern)
迭代器模式(Iterator Pattern)
观察者模式(Observer Pattern)
策略模式(Strategy Pattern)
状态模式(State Pattern)
备忘录模式(Memento Pattern)
模板方法模式(Template Pattern)
访问者模式(Visitor Pattern)
助记语:责令解中谍,观测状被模仿