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));
再用代理对象调用方法。
分享到:
相关推荐
其中,工厂模式是最常用的设计模式之一。工厂模式通过创建一个工厂类来封装对象的创建过程,使得客户端在使用对象时无需了解具体的创建细节,增强了系统的可扩展性和稳定性。例如,在EJB调用中,`em.create()`就类似...
为了更好地利用这些服务,开发者们总结了许多有效的设计模式,接下来将简要介绍几种常用的J2EE设计模式。 ##### 2.1 J2EE设计模式简介 J2EE设计模式主要关注于如何在J2EE环境中构建可伸缩、可维护的应用程序。这些...
工厂模式是最常用的设计模式之一,主要用于封装对象的创建过程。工厂模式的主要优点是解耦了创建过程和使用过程,系统可扩展性增强,稳定性增强。 例如,在面向对象编程中,一般一个 Class 都会继承一个接口,设定 ...
Java设计模式和J2EE设计模式是构建大型企业级应用的核心技术之一,它们提供了解决常见软件设计问题的标准模板。设计模式是经验丰富的开发者在实践中总结出的最佳实践,被广泛应用于J2EE多层系统架构中,包括架构设计...
### Java常用设计模式详解 #### 一、设计模式概述 设计模式是一种在特定情况下解决软件设计问题的经验总结,它能够帮助开发者在面对相似的问题时快速找到解决方案。设计模式大致可以分为三大类:创建型模式、结构...
本指南将深入探讨在J2EE环境中常用的设计模式,帮助开发者更好地理解和应用这些模式。 **1. 单例模式** 单例模式确保一个类只有一个实例,并提供一个全局访问点。在J2EE中,例如EJB(Enterprise JavaBeans)中的...
J2EE开发中常用的设计模式包括: **3.3 表示层模式** - **3.3.1 MVC (模型-视图-控制器)模式**:将应用程序分为三个部分:模型、视图和控制器。模型负责存储数据,视图负责显示数据,控制器则处理用户的输入。 - *...
### 与Spring技术相关的J2EE设计模式 #### 1. 工厂模式 ##### 1.1 什么是工厂模式? 工厂模式是一种常用的创建型设计模式,它提供了一个创建对象的接口,但允许子类决定实例化哪一个类。工厂方法让类的实例化推迟...
接下来,“设计模式-迷你手册”可能是一本简洁明了的参考指南,涵盖了基本的设计原则和一些最常用的设计模式。它可能包括创建型模式(如抽象工厂、工厂方法、建造者、单例)、结构型模式(如适配器、装饰器、代理、...
《J2EE核心模式》这本书深入探讨了J2EE开发中的常见设计模式,这些模式可以帮助开发者解决实际问题并提升代码质量。其中的一些关键模式包括: 1. **MVC(Model-View-Controller)模式**:将应用分为模型、视图和...
2.设计模式是比 J2EE 等框架软件更小的体系结构,J2EE 中许多具体程序都是应用设计模式来完成的,当你深入到 J2EE 的内 部代码研究时,这点尤其明显,因此,如果你不具备设计模式的基础知识(GoF 的设计模式),你很难...
《Core J2EE Patterns》是Java企业级应用开发的经典之作,它详细介绍了在J2EE平台上构建可扩展、高效、可维护的系统所使用的最佳实践和设计模式。这本书的第二版源码对于深入理解J2EE开发中的核心概念和技术具有极高...
在Java企业级应用开发中,DAO(Data Access Object)模式是一种常用的设计模式,它的主要目的是为了分离业务逻辑层和数据访问层,以提高代码的可重用性、可维护性和解耦。在"J2EE核心模式之DAO(简体中文)"这个资料中...
"业务代理"模式是J2EE应用中常见的设计模式,它在客户端和实际的业务对象之间添加了一个代理层,可以用于事务管理、安全性控制或者性能优化。 除此之外,书中还会介绍"会话bean"和"实体bean"这两种EJB(Enterprise ...
2. MVC模式:模型-视图-控制器(Model-View-Controller)模式是J2EE中推荐的一种设计模式,用于将业务逻辑与用户界面分离。其中,模型层负责业务数据和业务逻辑;视图层处理用户界面的显示;控制器层负责接收用户...
其中,工厂模式作为最常用的设计模式之一,是创建型模式的代表。 **工厂模式** 工厂模式的核心思想是提供一个工厂类,用来创建对象,从而将对象的创建过程封装起来,使得创建过程与使用过程解耦。这样做的好处是...
J2EE中还有其他常用设计模式,如: - **单例模式(Singleton)**:保证一个类只有一个实例,常用于配置管理或全局访问点。 - **工厂模式(Factory)**:提供对象创建的抽象接口,使得具体创建过程与使用对象的代码...