`

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

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




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;
	}
	
}



5
9
分享到:
评论

相关推荐

    Node.js-http-proxy-middleware用于把请求代理转发到其他服务器的中间件

    在 Node.js 开发中,`http-proxy-middleware` 是一款非常实用的中间件,主要用于将 HTTP 请求代理转发到其他服务器,这在构建 API 网关、微服务架构或者需要跨域访问时非常有用。这个中间件简化了配置过程,使得...

    研磨设计模式源码

    《研磨设计模式源码》是一份非常宝贵的资源,它提供了设计模式的实践代码,帮助开发者深入理解并应用这些模式。设计模式是软件工程中经过长期实践总结出来的一套通用解决方案,它们描述了在特定场景下如何解决常见...

    node-https-proxy-agent, HTTPS端点的HTTP代理 `http.Agent` 实现.zip

    node-https-proxy-agent, HTTPS端点的HTTP代理 `http.Agent` 实现 https-proxy-agent HTTPS的HTTP代理 http.Agent 实现 这个模块为连接到指定的HTTP或者HTTPS代理服务器提供了 http.Agent 实现,并且可以与内置的...

    研磨设计模式-part2

    第11章 代理模式(Proxy) 第12章 观察者模式(Observer) 第13章 命令模式(Command) 第14章 迭代器模式(Iterator) 第15章 组合模式(Composite) 第16章 模板方法模式(Template Method) 第17章 策略模式...

    influx-proxy-2.5.7-linux-amd64.tar.gz

    本文将详细探讨InfluxDB的核心特性和Influx-proxy的功能,并结合"Influx-proxy-2.5.7-linux-amd64.tar.gz"这个压缩包文件,解析其在Linux AMD64平台上可能的部署与使用。 首先,InfluxDB以其高效的存储和查询机制而...

    研磨设计模式-part4

    第11章 代理模式(Proxy) 第12章 观察者模式(Observer) 第13章 命令模式(Command) 第14章 迭代器模式(Iterator) 第15章 组合模式(Composite) 第16章 模板方法模式(Template Method) 第17章 策略模式...

    研磨设计模式-part3

    第11章 代理模式(Proxy) 第12章 观察者模式(Observer) 第13章 命令模式(Command) 第14章 迭代器模式(Iterator) 第15章 组合模式(Composite) 第16章 模板方法模式(Template Method) 第17章 策略模式...

    研磨设计模式 源代码

    《研磨设计模式》是一本深入探讨软件设计模式的经典书籍,源代码包含了书中所讲解的各种设计模式的实际应用示例。设计模式是软件工程中的重要概念,它们是经过反复验证、在特定情境下解决常见问题的有效解决方案。...

    docker-letsencrypt-nginx-proxy-companion-examples, 结合 Docker gen和 letsencrypt Nginx 代理伙伴的示例.zip

    docker-letsencrypt-nginx-proxy-companion-examples, 结合 Docker gen和 letsencrypt Nginx 代理伙伴的示例 docker-letsencrypt-nginx-proxy-companion-examples这个库是使用 nginx代理插件, docker gen和 docker-...

    ios-webkit-debug-proxy-1.9.0-win64-bin

    ios-webkit-debug-proxy-1.9.0-win64-bin

    C++设计模式--基于Qt4开源跨平台开发框架

    结构型模式如适配器模式(Adapter)、装饰器模式(Decorator)和代理模式(Proxy),则关注如何组合和连接类与对象,以达到新的功能。行为型模式如观察者模式(Observer)、策略模式(Strategy)和访问者模式...

    browsermob-proxy-2.1.4.zip

    browsermob-proxy-2.1.4,与selenium一起进行爬虫,获取network中的链接资源

    设计模式精解-GoF-23种设计模式解析--附C++源代码

    - 代理模式(Proxy):为其他对象提供一种代理以控制对这个对象的访问。 - 外观模式(Facade):提供一个统一的接口,用来访问子系统的一组接口。 - 适配器模式(Adapter):使两个接口不兼容的类能够协同工作。 ...

    charles-proxy-4.5.6-win64

    charles 解压就能用 charles-proxy-4.5.6-win64

    apache开源项目源码commons-proxy-1.0-src(全部高质量代理模式proxy的java源程序)

    java.proxy,代理模式源码,设计模式,apache开源项目源码commons-proxy-1.0-src 各种代理模式操作的工具类源码以及代理模式案例源码,你会从中得到意想不到的效果! apache开源组织开发的开源项目源码,其优良的代码...

    mysql-proxy-0.8.5-windows-x86-32bit

    `mysql-proxy-0.8.5-windows-x86-34bit` 是 MySQL Proxy 的一个特定版本,适用于32位Windows操作系统。 MySQL Proxy 的主要功能和优势包括: 1. **透明代理**:MySQL Proxy 可以悄无声息地插入到客户端和服务器...

    smiley-http-proxy-servlet-1.7.jar

    java运行依赖jar包

    goproxy-android snail007/goproxy全能代理服务器安卓版

    《GoProxy-Android:全能代理服务器在安卓平台的应用与实现》 GoProxy-Android是由snail007/goproxy团队开发的一款适用于安卓系统的全能代理服务器应用。此项目旨在为移动设备提供强大的网络代理功能,使得用户能够...

    研磨设计模式(完整带书签).part2.pdf

    第11章 代理模式(Proxy) 第12章 观察者模式(Observer) 第13章 命令模式(Command) 第14章 迭代器模式(Iterator) 第15章 组合模式(Composite) 第16章 模板方法模式(Template Method) 第17章 策略模式...

Global site tag (gtag.js) - Google Analytics