读《研磨设计模式》-代码笔记-代理模式-Proxy

[b]声明:
本文只为方便我个人查阅和理解,详细的分析以及源代码请移步 原作者的博客[url]http://chjavach.iteye.com/[/url][/b]




import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;

/*
* 下面的代码关注两种代理:
* 1.虚代理
* 2.保护代理
*/

/*
* 订单类接口
* id 订单id
* name 订单名称
*/
interface IOrder {

void setName(String name);

void setID(String id);

String getName();

String getID();

}

class Order implements IOrder {

private String id;

private String name;

public String getName() {
return this.name;
}

public void setName(String name) {
this.name = name;
}

public String getID() {
return this.id;
}

public void setID(String id) {
this.id = id;
}

}


class OrderProxy implements IOrder {

private Order order;

private boolean nameLoaded;

public OrderProxy(Order order) {
this.order = order;
this.nameLoaded = false;
}

/*
* 1、虚代理
* a. 客户查询订单信息时,只查询客户要求的信息:订单ID(假设这个查询比较快)
* b. 只有当用户要求更详细的信息(假设只是一个订单名称)时,才再次到数据库查询
* 这样做的原因是,通常查询“详细信息”时,会花费更多的时间和空间,有点“延迟加载”的感觉
*/
private void loadName() {
if (!nameLoaded) {
System.out.println("request name but no name, fetch it from database:");
String name = "aName"; //模拟数据库操作
order.setName(name);
this.nameLoaded = true;
}
}

public String getID() {
return order.getID();
}

/*
* 2.保护代理,可以在这里加上条件,符合则调用真实的order的方法。例如只有订单创建者能修改订单名称
*/
public void setName(String name) {
boolean canChangeName = true; //根据实际设置,例如canChangeName = (name.equals(order.getCreateUser()));
if (canChangeName) {
order.setName(name);
System.out.println("Request accepted. Name changed.");
}
}

public void setID(String id) {
order.setID(id);
}

public String getName() {
if (!nameLoaded) {
this.loadName();
}
return this.order.getName();
}

}


public class ProxyPattern {

public static void main(String[] args) {

//1.静态代理
ProxyPattern p = new ProxyPattern();
IOrder order = p.getOrderFromDatabase(); //模拟从数据库查询Order
System.out.println("id:" + order.getID());

//测试虚代理。如果“客户”没有调用getName,那“到数据库查询name”这个操作就可以不执行了
System.out.println("name:" + order.getName());

//测试保护代理
order.setName("newName");
System.out.println(order.getName());

//2.动态代理
//准备测试数据
Order order2 = new Order();
order2.setID("originalID");
order2.setName("originalName");
DynamicProxy dProxy = new DynamicProxy();
IOrder iOrder = dProxy.getProxyOrder(order2);
iOrder.setID("anotherID");
iOrder.setName("anotherName");
System.out.println(iOrder.getID() + ","+ iOrder.getName());
}

//模拟从数据库查询Order
public IOrder getOrderFromDatabase() {
//这里创建的是代理,而非真实的Order
//IOrder order = new Order();
OrderProxy proxy = new OrderProxy(new Order());
System.out.println("simple info. Only fetch order's id from database:");
String id = "aID"; //模拟从数据库取得ID
proxy.setID(id);
return proxy;
}
}


//=======================以上实现代理的方式称为静态代理===========================================

/**
* JDK里面的InvocationHandler来实现代理,称为动态代理
* 静态代理实现的时候,在Subject接口(IOrder)上定义很多的方法,代理类里面自然也要实现很多方法;
* 而动态代理实现的时候,虽然Subject接口上定义了很多方法,但是动态代理类始终只有一个invoke方法。
* 这样当Subject接口发生变化的时候,动态代理的接口就不需要跟着变化了。
* Java的动态代理目前只能代理接口,基本的实现是依靠Java的反射机制和动态生成class的技术,来动态生成被代理的接口的实现对象。
*/
class DynamicProxy implements InvocationHandler{

private IOrder order;

public IOrder getProxyOrder(Order order) {
this.order = order;
//把真正的订单对象和动态代理关联起来
IOrder iOrder = (IOrder) Proxy.newProxyInstance(order.getClass().getClassLoader(),
order.getClass().getInterfaces(),
this);
return iOrder;
}

/*
* 这个方法并不需要我们显式的调用
* 我们在getProxyOrder后获得一个IOrder,当IOrder调用某方法时,会触发invoke()这个方法
* 也就是所有方法调用都被invoke()拦截了
* 这里面的第一个参数obj是什么呢?看API的说法是“proxy instance”。一般不用到这一个参数
* passing the proxy instance,a java.lang.reflect.Method object identifying the method that was invoked,
* and an array of type Object containing the arguments.
*/
public Object invoke(Object obj, Method method, Object[] aobj) throws Throwable {
Object result = null;

//假设不允许执行setID操作
if (method.getName().equalsIgnoreCase("setID")) {
System.out.println(method.getName() + ":Access denied.");
} else {
//result = method.invoke(obj, aobj); //不能这样写
result = method.invoke(order, aobj); //调用真实的order的method
}
//System.out.println(String.format("Invoke '%s' ; result = %s", method.getName(), result));
return result;
}

}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值