设计模式 - 代理模式(Proxy)

Proxy模式为其他对象提供一种代理以控制对这个对象的访问。

类图
这里写图片描述

下面是一些可以使用Proxy模式常见情况:

  1. 远程代理(Remote Proxy)为一个对象在不同的地址空间提供局部代表。
  2. 虚代理(Virtual Proxy)根据需要创建开销很大的对象。
  3. 保护代理(Protection Proxy)控制对原始对象的访问。保护代理用于对象应该有不同的访问权限的时候。
  4. 智能指引(Smart Reference)取代了简单的指针,它在访问对象时执行一些附加操作。它的典型用途包括:对指向实际对象的引用计数,这样当该对象没有引用时,可以自动释放。

案例 1: Virtual Proxy

public interface FileHandler {
	public void readFile();
}
public class TextFileHandler implements FileHandler {
	private File file;
	
	public TextFileHandler(String fileName) {
		file = new File(fileName);
	}

	public void readFile() {
		StringBuilder stringBuilder = new StringBuilder();
		FileReader in = null;
		try {
			in = new FileReader(file);
			BufferedReader buffIn = new BufferedReader(in);
			String line = null;
			while((line = buffIn.readLine()) != null) {
				stringBuilder.append(line);
			}
			buffIn.close();
			System.out.println(stringBuilder.toString());
		} catch (Exception e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}
}
public class TextFileHandlerProxy implements FileHandler{
	private TextFileHandler handler;
	private String fileName;
	public TextFileHandlerProxy(String fileName) {
		this.fileName = fileName;
	}
	public FileHandler getHandler() {
		if(handler == null) {
			handler = new TextFileHandler(fileName);
		}
		return handler;
	}
	public void readFile() {
		getHandler().readFile();
	}
}

客户代码在创建TextFileHandlerProxy对象时,没有实例化被代理的对象 TextFileHandler,也就没有创建File对象,当调用readFile方法, 才开始创建被代理对象的一个拷贝,进而创建File对象。
另外一种方式,在代理对象中开启一个线程创建开销很大的被代理对象。

案例 2: RMI 远程代理, 分布式对象之间的通讯。

定义远程接口

public interface MyRemote extends Remote {
	public String sayHello() throws RemoteException;
}

实现远程接口

public class MyRemoteImpl extends UnicastRemoteObject implements MyRemote {
	protected MyRemoteImpl() throws RemoteException {
		super();
	}
	public String sayHello() throws RemoteException {
		return "Hello, World!";
	}
	public static void main(String[] args) {
		try {
			MyRemote service = new MyRemoteImpl();
			Registry registry = LocateRegistry.createRegistry(8888);
			registry.bind("RemoteHello", service); //Binds a remote reference to the specified name in this registry.
		} catch (Exception e) {
			e.printStackTrace();
		}
	}
}

访问远程对象

public class MyRemoteClient {
	public static void main(String[] args) {
		new MyRemoteClient().go();
	}
	public void go() {
		try {
			MyRemote service = (MyRemote)Naming.lookup("rmi://127.0.0.1:8888/RemoteHello");//反序列化返回Stub对象,客户端要有stub 类
			System.out.println(service.sayHello());
		} catch (Exception e) {
			e.printStackTrace();
		}
	}
}

案例3: 通过JDK 动态代理 实现保护代理。

定义被代理对象(subject)的接口 (必须)

public interface Person {
	String getName();
	void setName(String name);
	double getSalary();
	void setSalary(double salary);
}

定义被代理对象

public class PersonImpl implements Person {
	private String name;
	private double salary;
	public PersonImpl(String name, double salary) {
		this.name = name;
		this.salary = salary;
	}
	public String getName() {
		return name;
	}
	public void setName(String name) {
		this.name = name;
	}
	public double getSalary() {
		return salary;
	}
	public void setSalary(double salary) {
		salary = salary;
	}
}

定义调用处理器,客户调用代理对象的方法,将被派遣到调用处理器invoke方法,再通过Method对象调用被代理对象的方法。

public class MyInvocationHandler implements InvocationHandler {
	private Object target; //reference of subject
	public Object bind(Object target) {
		this.target = target;
		return Proxy.newProxyInstance(target.getClass().getClassLoader(), target.getClass().getInterfaces(), this);
	}
	public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
		if(method.getName().startsWith("get")) {
		   System.out.println("invoking method " + method.getName());
			return method.invoke(person, args);
		} else { //protect setter method
		    throw new IllegalAccessException("It is not accessable");
		}
	}
}

客户代码

public class ProxyClient {
	public static void main(String[] args) {
		Person person = new PersonImpl("Tom", 8000); //If use JDK dynamic proxy, subject must implement an interface
		MyInvocationHandler  handler = new MyInvocationHandler ();
		Person proxy = (Person)handler.bind(person));
		try {
			proxy.setSalary(9999); // this method is protected, can not change salary
		} catch (Exception e) {
			System.out.println("message=" + e.getCause().getMessage());
		}
	}
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值