代理模式介绍
代理模式(Proxy Pattern),就是一个类可以代表另一个类的功能。这种类型的设计模式属于结构性模式。
为了使代理类和被代理类有相同的功能,通常实现同一个接口。
作用:为对象A提供一种代理用来控制这个对象A
主要解决问题: 在直接访问对象时带来的问题,比如对象在不同的进程(即跨进程),对象在远程服务器上等。对象由于某些原因,直接去访问会给使用者或者系统结构带来很多麻烦(创建对象消耗很大,某些操作需要安全控制/权限问题)等,因此我们在访问这个对象时加上一个对此对象的访问层(即代理类)。
解决方法: 增加中间层(即代理类)
关键代码: 在代理类中实现与被代理类的组合。
应用举例: 1.Windows里面的快捷方式; 2.买火车票不一定去火车站,可以通过代售点; 3.支票对现金的代理,可以用支票代替现金。
优点: 1.职责清晰; 2.高扩展性,可以在代理中扩展功能; 3.智能化。
缺点: 1.由于在客户端和真实对象间增加了代理对象,因此有些类型的代理模式可能会造成请求变慢;2.实现代理需要额外的工作,有些代理模式实现非常复杂。
使用场景
1) 远程代理(Remote Proxy)为一个位于不同的地址空间的对象提供一个本地的代理对象。这个不同的地址空间可以是在同一台主机中,也可是在另一台主机中,远程代理又叫做大使(Ambassador)
2) 虚拟代理(Virtual Proxy)根据需要创建开销很大的对象。如果需要创建一个资源消耗较大的对象,先创建一个消耗相对较小的对象来表示,真实对象只在需要时才会被真正创建。
3) 保护代理(Protection Proxy)控制对原始对象的访问。保护代理用于对象应该有不同的访问权限的时候。
4) 智能指引(Smart Reference)取代了简单的指针,它在访问对象时执行一些附加操作。
5) Copy-on-Write代理:它是虚拟代理的一种,把复制(克隆)操作延迟到只有在客户端真正需要时才执行。一般来说,对象的深克隆是一个开销较大的操作,Copy-on-Write代理可以让这个操作延迟,只有对象被用到的时候才被克隆。
代理模式 代码示例
首先擦混个建一个IMovie接口,然后RealMovie是实现了接口的实体类,ProxyMovie是实现了接口的代理类,ProxyPartten是使用代理类的业务代码。 以下是类图:
第一步,创建接口
public interface IMovie {
void displayMovie();
void loadMovie(String filename);
}
第二步,创建实现接口的实体类
public class RealMovie implements IMovie{
private String mFilename;
public RealMovie(String filename) {
this.mFilename = filename;
}
@Override
public void displayMovie() {
System.out.println("播放视频");
}
@Override
public void loadMovie(String filename) {
System.out.println("执行加载视频文件:" + filename);
}
}
第三步,创建实现接口的代理类
public class ProxyMovie implements IMovie{
private String mFilename;
private RealMovie mRealMovie;
public ProxyMovie(String filename) {
this.mFilename = filename;
}
@Override
public void displayMovie() {
if(mRealMovie == null) {
mRealMovie = new RealMovie(mFilename);
}
mRealMovie.displayMovie();
}
@Override
public void loadMovie(String filename) {
if(mRealMovie == null) {
mRealMovie = new RealMovie(filename);
}
mRealMovie.loadMovie(filename);
}
}
第四步, 在业务代码中使用代理类
public class Proxypartten {
public static void main(String[] args) {
ProxyMovie proxyMovie = new ProxyMovie("大话西游之月光宝盒");
proxyMovie.displayMovie();
}
}
以上就是对代理模式的介绍, 但其实代理模式在实际使用中,还会有划分:静态代理、动态代理、CgLib代理。 通常我们所说的就是上面举例提到的静态代理, 下面再简单介绍下动态代理和CgLib代理。
动态代理
动态代理有以下特点:
- 1.代理对象,不需要实现接口
- 2.代理对象的生成,是利用JDK的API,动态的在内存中构建代理对象(需要我们指定创建代理对象/目标对象实现的接口的类型)
- 3.动态代理也叫做:JDK代理,接口代理
JDK中生成代理对象的API
代理类所在包:java.lang.reflect.Proxy
JDK实现代理只需要使用newProxyInstance方法,但是该方法需要接收三个参数,完整的写法是:
static Object newProxyInstance(ClassLoader loader, Class
Cglib代理
上面的静态代理和动态代理模式都是要求目标对象是实现一个接口的目标对象,但是有时候目标对象只是一个单独的对象,并没有实现任何的接口,这个时候就可以使用以目标对象子类的方式类实现代理,这种方法就叫做:Cglib代理
Cglib代理,也叫作子类代理,它是在内存中构建一个子类对象从而实现对目标对象功能的扩展.
- JDK的动态代理有一个限制,就是使用动态代理的对象必须实现一个或多个接口,如果想代理没有实现接口的类,就可以使用Cglib实现.
- Cglib是一个强大的高性能的代码生成包,它可以在运行期扩展java类与实现java接口.它广泛的被许多AOP的框架使用,例如Spring AOP和synaop,为他们提供方法的interception(拦截)
- Cglib包的底层是通过使用一个小而块的字节码处理框架ASM来转换字节码并生成新的类.不鼓励直接使用ASM,因为它要求你必须对JVM内部结构包括class文件的格式和指令集都很熟悉.
Cglib子类代理实现方法:
1.需要引入cglib的jar文件,但是Spring的核心包中已经包括了Cglib功能,所以直接引入pring-core-3.2.5.jar即可.
- 2.引入功能包后,就可以在内存中动态构建子类
- 3.代理的类不能为final,否则报错
- 4.目标对象的方法如果为final/static,那么就不会被拦截,即不会执行目标对象额外的业务方法.
这一部分的使用可以自行百度, 对于Android开发来讲, 没有CgLib,但也有类似的功能。