`
Strive_sprint
  • 浏览: 21667 次
  • 性别: Icon_minigender_1
  • 来自: 长沙
社区版块
存档分类
最新评论

j2ee常用设计模式之代理模式

 
阅读更多

 

1.什么是代理模式

      为其他对象提供一种代理以控制这个对象的访问,这就是代理模式(百度文库)。我的理解就是当程序不希望用户直接访问目的对象时,在用户对象和目的对象之间插入一个对象,这个对象作为目的对象的代理,代理通过调用目的对象的相应方法达到用户对象的要求。

 

2.代理模式的角色

      ①.抽象主题(Subject):抽象主题是一个接口,是对象和它的代理共有的接口。

      ②.实际主题(RealSubject):实际主题的实例是代理对象所要代理的对象。

      ③.代理(Proxy):代理含有主题接口声明的变量,存放实际主题的实例,这样就可以控制对实际主题的访问。

 

3.代理类的作用

      代理类不但可以控制对实际主题的访问,而且还主要负责为实际主题预处理消息、过滤消息、把消息转发给实际主题,以及事后处理消息等。

 

看下面的例子

    抽象主题:

public interface Geometry {
	//得到三角形面积的方法
	public double getArea();
}

  实际主题:

public class Triangle implements Geometry {
	//三角形的三边
	private double sideA,sideB,sideC;
	public Triangle(double a,double b,double c){
		sideA = a;
		sideB = b;
		sideC = c;
	}
	@Override
	public double getArea() {
		//根据海伦公式求面积
		double p = (sideA+sideB+sideC)/2.0;
		double area = Math.sqrt(p*(p-sideA)*(p-sideB)*(p-sideC));
		return area;
	}
}

  代理:

public class TriangleProxy implements Geometry {
	//三角形的三边
	private double sideA,sideB,sideC;
	//声明实际三角形对象
	private Triangle triangle;
	//构造函数,传入三角形三边的值
	public TriangleProxy(double a,double b,double c){
		sideA = a;
		sideB = b;
		sideC = c;
	}
	@Override
	public double getArea() {
		//根据定理判定这三边能不能组成一个三角形
		if(sideA+sideB>sideC&&sideA+sideC>sideB&&sideB+sideC>sideA){
			System.out.println("能组成一个三角形");
			//创建实际三角形对象
			triangle = new Triangle(sideA,sideB,sideC);
			double area = triangle.getArea();
			return area;
		}else{
			System.out.println("输入数据不能组成一个三角形");
			return -1;
		}
	}
}

  测试类:

public class Application {
	public static void main(String [] args){
		//创建代理对象
		TriangleProxy proxy = new TriangleProxy(20,22,26);
		//调用代理类求面积的方法
		double area = proxy.getArea();
		System.out.println("面积是:"+area);
	}
}

 

结果:

能组成一个三角形
面积是:213.7662274541982
      从上面的例子可以看出,用户根本没有直接访问实际对象(Triangle),而是访问的代理对象(TriangleProxy),通过访问代理来达到访问实际对象的目的。当输入数据满足一个三角形的时候,才创建实际对象,如果不满足则不创建,这也达到了预处理消息,过滤消息的作用

 

      但是这也有个问题,如果有很多类实现Geometry接口,而且实现类都有代理类,当Geometry接口中再定义一个求三角形周长的方法时,那么所有的代理类都要修改。这可不是我们想看到的结果,这时就需要动态代理了

 

4.按代理创建的时期可以分为静态代理和动态代理

      静态代理:由程序员创建或特定工具自动生成源代码,再对其编译。在程序运行前,代理类的.class文件就已经存在了(上例)。

      动态代理:在程序运行时,运用反射机制动态创建而成。

 

5.动态代理的实现

      动态代理与静态代理相比较,最大的好处是接口中声明的所有方法都被转移到一个集中的方法中处理(invoke()方法),这样,在接口方法数量比较多的时候,我们可以进行灵活处理,而不需要像静态代理那样每一个方法进行中转。

      动态代理只能代理接口,主要依赖于java.lang.reflect包下面的InvocationHandler接口和Proxy类,其中InvocationHandler接口只提供了一个方法:public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {},这里proxy指被代理的对象,即实际对象,method指要调用的方法,args指方法调用时所需要的参数。Proxy类主要方法是public static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler handler) throws IllegalArgumentException{},这里loader是指类加载器(后面分析JVM的时候再分析),interfaces指被代理的接口,可以是一个或者多个,handler指InvocationHandler接口实现类的对象。

 

看下面的例子:

   抽象主题:

public interface Geometry {
	//得到三角形面积的方法
	public double getArea(double a,double b,double c);
	//得到三角形周长的方法
	public double getPerimeter(double a,double b,double c);
}

 实际主题:

public class Triangle implements Geometry {
	@Override
	public double getArea(double a, double b, double c) {
		double p = (a+b+c)/2.0;
		double area = Math.sqrt(p*(p-a)*(p-b)*(p-c));
		return area;
	}
	@Override
	public double getPerimeter(double a, double b, double c) {
		return a+b+c;
	}
}

   代理:

public class TriangleProxy implements InvocationHandler {
	//实际对象
	private Object target;
	//得到实际对象的代理对象
	public Object getProxy(Object target){
		this.target = target;
		return Proxy.newProxyInstance(target.getClass().getClassLoader(), target.getClass().getInterfaces(), this);
	}
	@Override
	public Object invoke(Object proxy, Method method, Object[] args)
			throws Throwable {
		//得到方法的参数,参数是Object类型,用的时候需要强制转型
		for(int i = 0;i<args.length;i++){
			System.out.println(args[i]);
		}
		return method.invoke(target, args);
	}
}

 测试类:

public class Test {
	public static void main(String [] args){
		Geometry geometry = new Triangle();
		TriangleProxy tp = new TriangleProxy();
		//得到代理对象
		Geometry proxy = (Geometry) tp.getProxy(geometry);
		//代理对象调用方法
		double area = proxy.getArea(20, 22, 26);
		System.out.println("面积为:"+area);
		double perimeter = proxy.getPerimeter(2, 3, 4);
		System.out.println("周长为:"+perimeter);
	}
}

 

结果:

20.0
22.0
26.0
面积为:213.7662274541982
2.0
3.0
4.0
周长为:9.0
      可以看出,不管Geometry接口里面再加多少方法,TriangleProxy类中都不用修改,只要在测试类中调用相应的方法。而且参数已经得到args[],可以根据这个进行预处理和过滤。这里需要指出,我们没有显示的调用TriangleProxy类中的invoke()方法,那写着有什么用呢?其实则不然,其实虽然我们在测试类中写的proxy.getArea(),但是实际上调用的是TriangleProxy类中的invoke()方法,然后在invoke()方法中调用了getArea()方法,看invoke()方法中的一句代码method.invoke(target, args),前面也反射介绍了,target对象调用了方法method,参数是args

      那我们在invoke()方法中加上这么一句,也许你能看明白:

@Override
public Object invoke(Object proxy, Method method, Object[] args)
		throws Throwable {
	System.out.println("正在执行的方法:"+method);//加这句
	//得到方法的参数,参数是Object类型,用的时候需要强制转型
	for(int i = 0;i<args.length;i++){
		System.out.println(args[i]);
	}
	return method.invoke(target, args);
}

 结果:

正在执行的方法:public abstract double test.Geometry.getArea(double,double,double)
20.0
22.0
26.0
面积为:213.7662274541982
正在执行的方法:public abstract double test.Geometry.getPerimeter(double,double,double)
2.0
3.0
4.0
周长为:9.0
      是不是豁然开朗。

 

      当然其实得到代理对象的方法也可以写在测试类中,那么在TriangleProxy类中去掉得到代理对象的方法,加上一个带参构造函数:

public TriangleProxy(Object target){
	this.target = target;
}

 在测试类中得到代理对象:

Geometry geometry = new Triangle();
//得到代理对象
Geometry proxy = (Geometry) Proxy.newProxyInstance(geometry.getClass().getClassLoader(),
geometry.getClass().getInterfaces(), new TriangleProxy(geometry));

 再用代理对象调用方法。 

分享到:
评论

相关推荐

    与Spring技术相关的J2EE设计模式

    共讲解了5种设计模式:工厂模式,抽象工厂,单例设计模式Singleton,业务代理(Business Delegate)类模式(或者:Proxy模式),模板(Template)方法模式. 从设计思路,特点,作用,常用方法等多方面讲解,有示例代码

    二十三种设计模式【PDF版】

    2.设计模式是比 J2EE 等框架软件更小的体系结构,J2EE 中许多具体程序都是应用设计模式来完成的,当你深入到 J2EE 的内 部代码研究时,这点尤其明显,因此,如果你不具备设计模式的基础知识(GoF 的设计模式),你很难...

    J2EE应用开发详解

    内容为J2EE应用开发详解中的源代码 第1章 Java Web应用开发简介 1 1.1 Java EE应用概述 1 1.2 Java EE概念 1 1.2.1 Java EE多层模型 1 1.2.2 Java EE体系结构 2 1.3 Java EE的核心API与组件 4 1.4 Web服务器和应用...

    王勇drp项目分析web开发分析

    掌握常用的GoF和J2EE设计模式 掌握分层架构思想 了解SCM 了解XML,XSL、DTD和Schema 了解异构系统整合模式,了解Web Services技术体系 掌握建模工具Rational Rose和PowerDesigner 掌握Oracle的基本使用 掌握程序的...

    SMART系统-系统框架设计与开发

    javaSMART系统是一个新型智能在线考试信息管理系统,该系统主要实现了学生在线考试与评估以及教师对学生在线考试信息的管理和维护。本文按照SMART系统的非功能性需求,...关键词:设计模式;开源;领域建模;系统框架

    JAVA SMART系统-系统框架设计与开发(源代码+论文)

    SMART系统-系统框架设计与开发 摘 要 SMART系统是一个新型智能在线考试信息管理系统,该系统主要实现了学生在线考试与评估以及教师对学生在线考试信息的管理和维护。...关键词:设计模式;开源;领域建模;系统框架

    JAVA SMART系统-系统框架设计与开发程序源代码毕业论文

    在业务层则是采用单例模式设计与Spring的IoC模式相结合,实现了公共代理类的编写,各业务逻辑接口的封装。而在持久层的设计中则是采用基于现有持久层框架的实现模式,实现了对产生Session实例的封装,对常用数据库...

    -SMART系统-系统框架设计与开发.zipspringbootSMART系统是一个新型智能在线考试信息管理系统,该系统主要实现

    springbootSMART系统是一个新型智能在线考试信息管理系统,该系统主要实现了学生在线考试与评估以及教师对学生在线考试信息的管理和维护。本文按照SMART系统的非功能性...关键词:设计模式;开源;领域建模;系统框架

    JAVA SMART系统-系统框架设计与开发(源代码+论文).rar

    在业务层则是采用单例模式设计与Spring的IoC模式相结合,实现了公共代理类的编写,各业务逻辑接口的封装。而在持久层的设计中则是采用基于现有持久层框架的实现模式,实现了对产生Session实例的封装,对常用数据库...

    基于JAVA SMART系统-系统框架设计与开发(毕业设计+lw)

    在业务层则是采用单例模式设计与Spring的IoC模式相结合,实现了公共代理类的编写,各业务逻辑接口的封装。而在持久层的设计中则是采用基于现有持久层框架的实现模式,实现了对产生Session实例的封装,对常用数据库...

    asp.net知识库

    我对J2EE和.NET的一点理解 难分难舍的DSO(一) InternalsVisibleToAttribute,友元程序集访问属性 Essential .NET 读书笔记 [第一部分] NET FrameWork的Collections支持 .NET的反射在软件设计上的应用 关于跨程序集...

    SMART系统-系统框架设计与开发(JAVA)

    在业务层则是采用单例模式设计与Spring的IoC模式相结合,实现了公共代理类的编写,各业务逻辑接口的封装。而在持久层的设计中则是采用基于现有持久层框架的实现模式,实现了对产生Session实例的封装,对常用数据库...

    计算机毕业设计 - JAVA SMART系统-系统框架设计与开发(源代码+论文),保证可靠运行,提供示范论文可供参考

    在业务层则是采用单例模式设计与Spring的IoC模式相结合,实现了公共代理类的编写,各业务逻辑接口的封装。而在持久层的设计中则是采用基于现有持久层框架的实现模式,实现了对产生Session实例的封装,对常用数据库...

    毕业设计-基于JAVA的系统框架设计与开发(源代码+论文)

    在业务层则是采用单例模式设计与Spring的IoC模式相结合,实现了公共代理类的编写,各业务逻辑接口的封装。而在持久层的设计中则是采用基于现有持久层框架的实现模式,实现了对产生Session实例的封装,对常用数据库...

    java 面试题 总结

    assertion(断言)在软件开发中是一种常用的调试方式,很多开发语言中都支持这种机制。在实现中,assertion就是在程序中的一条语句,它对一个boolean表达式进行检查,一个正确程序必须保证这个boolean表达式的值为...

    超级有影响力霸气的Java面试题大全文档

    assertion(断言)在软件开发中是一种常用的调试方式,很多开发语言中都支持这种机制。在实现中,assertion就是在程序中的一条语句,它对一个boolean表达式进行检查,一个正确程序必须保证这个boolean表达式的值为...

Global site tag (gtag.js) - Google Analytics