目标:
1、为另一个对象提供一个代理去控制对它的访问
2、使用一种间接的方式来支持分布式的、受控制的或者智能的访问
3、增加一个包装器和委托来避免给实际的组件带来过多的复杂性
问题:
你需要支持资源消耗严重的对象,但是你又不想实例化这样的对象,除非the client真的需要这些对象。
讨论:
设计一个代理对象:在the client第一次请求代理的时候,实例化实际的对象,记住这个实际对象的标识,将请求转发给这个实际对象。然后所有接下来的请求都被直接转发给这个封装过的实际对象。
代理模式适合应用到如下的四种场景:
1、一个虚拟代理是创建开销比较大的对象的一个占位符。实际的对象仅仅在client第一次请求的时候创建。
2、一个远程代理为一个生存在不同地址空间的对象提供了一个本地的表示。这就是RPC和CORBA提供的stub代码。
3、一个保护性质的代理控制着对一个主要对象的访问。这个代理在转发请求之前检查调用者是否有权限访问。
4、一个智能代理当一个对象被访问的时候插入额外的行为。典型的使用包括:
- 对实际对象的引用数量计数,使得当没有引用的时候能够自动释放资源。
- 当实际对象第一次被引用的时候,加载一个持久对象到内存中。
- 在实际对象被访问之前检查是否是被锁住的,保证没有其他的对象在这个时候可以改变它的状态。
结构:
定义一个Subject接口,Client与Proxy交互,RealSubject对Client是透明的。
经验法则:
1、适配器给它的subject提供了一个不同的接口,Proxy提供了相同的接口,装饰器提供了一个增强的接口。
2、装饰器和代理具有不同的作用但是有相似的结构。都描述了如何为另一个对象提供一个间接的访问,它们的实现中都保持了一个对实际对象的引用。
代码示例:
import java.io.*;
import java.net.*;
// 5. To support plug-compatibility between
// the wrapper and the target, create an interface
interface SocketInterface {
String readLine();
void writeLine(String str);
void dispose();
}
public class ProxyDemo {
public static void main(String[] args) {
// 3. The client deals with the wrapper
SocketInterface socket = new SocketProxy("127.0.0.1", 8189,
args[0].equals("first") ? true : false);
String str = null;
boolean skip = true;
while (true) {
if (args[0].equals("second") && skip) {
skip = !skip;
} else {
str = socket.readLine();
System.out.println("Receive - " + str); // java ProxyDemo first
if (str.equals("quit")) {
break; // Receive - 123 456
}
} // Send ---- 234 567
System.out.print("Send ---- "); // Receive - 345 678
str = Read.aString(); //
socket.writeLine(str); // java ProxyDemo second
if (str.equals("quit")) {
break; // Send ---- 123 456
}
} // Receive - 234 567
socket.dispose(); // Send ---- 345 678
}
}
class SocketProxy implements SocketInterface {
// 1. Create a "wrapper" for a remote,
// or expensive, or sensitive target
private Socket socket;
private BufferedReader in;
private PrintWriter out;
public SocketProxy(String host, int port, boolean wait) {
try {
if (wait) {
// 2. Encapsulate the complexity/overhead of the target in the wrapper
ServerSocket server = new ServerSocket(port);
socket = server.accept();
} else {
socket = new Socket(host, port);
}
in = new BufferedReader(new InputStreamReader(
socket.getInputStream()));
out = new PrintWriter(socket.getOutputStream(), true);
} catch (IOException e) {
e.printStackTrace();
}
}
public String readLine() {
String str = null;
try {
str = in.readLine();
} catch (IOException e) {
e.printStackTrace();
}
return str;
}
public void writeLine(String str) {
// 4. The wrapper delegates to the target
out.println(str);
}
public void dispose() {
try {
socket.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
Reference: http://sourcemaking.com/design_patterns/proxy