文档章节

【设计模式】-代理模式

fengsehng
 fengsehng
发布于 2016/11/09 09:12
字数 2059
阅读 2
收藏 0

模式动机

在某些情况下,一个客户不想或者不能直接引用一个对 象,此时可以通过一个称之为“代理”的第三者来实现 间接引用。代理对象可以在客户端和目标对象之间起到 中介的作用,并且可以通过代理对象去掉客户不能看到 的内容和服务或者添加客户需要的额外服务。

通过引入一个新的对象(如小图片和远程代理 对象)来实现对真实对象的操作或者将新的对 象作为真实对象的一个替身,这种实现机制即 为代理模式,通过引入代理对象来间接访问一 个对象,这就是代理模式的模式动机。

模式定义

代理模式(Proxy Pattern) :给某一个对象提供一个代 理,并由代理对象控制对原对象的引用。代理模式的英 文叫做Proxy或Surrogate,它是一种对象结构型模式。

分类:

1.静态代理

2.动态代理

静态代理:

所谓静态代理,就是在编译阶段就生成代理类来完成对代理对象的一系列操作。下面是代理模式的结构类图:

代理模式的角色分四种:

主题接口: 即代理类的所实现的行为接口。
目标对象: 也就是被代理的对象。
代理对象: 用来封装真是主题类的代理类
客户端

下面是代理模式的类图结构:

这里写图片描述

代理模式的实现思路

代理对象和目标对象均实现同一个行为接口。
代理类和目标类分别具体实现接口逻辑。
在代理类的构造函数中实例化一个目标对象。
在代理类中调用目标对象的行为接口。
客户端想要调用目标对象的行为接口,只能通过代理类来操作。

实例:

静态代理的实例

下面以一个延迟加载的例子来说明一下静态代理。我们在启动某个服务系统时,加载某一个类时可能会耗费很长时间。为了获取更好的性能,在启动系统的时候,我们往往不去初始化这个复杂的类,取而代之的是去初始化其代理类。这样将耗费资源多的方法使用代理进行分离,可以加快系统的启动速度,减少用户等待的时间。

定义一个主题接口

public interface Subject {
    public void sayHello();
    public void sayGoodBye();
}

定义一个目标类, 并实现主题接口

public class RealSubject implements Subject {
    public void sayHello() {
        System.out.println("Hello World");
    }

    public void sayGoodBye() {
        System.out.println("GoodBye World");
    }
}

定义一个代理类,来代理目标对象

public class StaticProxy implements Subject {

    Private RealSubject realSubject = null;

    public StaticProxy() {}

    public void sayHello() {
        //用到时候才加载,懒加载
        if(realSubject == null) {
            realSubject = new RealSubject();
        }
        realSubject.sayHello();
    }

    //sayGoodbye方法同理
    ...
}

定义一个客户端

public class Client {
    public static void main(String [] args) {
        StaticProxy sp = new StaticProxy();
        sp.sayHello();
        sp.sayGoodBye();
    }
}

以上就是静态代理的一个简单测试例子。感觉可能没有实际用途。然而并非如此。使用代理我们还可以将目标对象的方法进行改造,比如数据库连接池中创建了一系列连接,为了保证不频繁的打开连接,这些连接是几乎不会关闭的。然而我们编程总有习惯去将打开的 Connection 去 close 。 这样我们就可以利用代理模式来重新代理 Connection 接口中的 close 方法,改变为回收到数据库连接池中而不是真正的执行 Connection.close 方法。其他的例子还有很多,具体需要自己体会

动态代理:

动态代理是指在运行时动态生成代理类。即,代理类的字节码将在运行时生成并载入当前代理的 ClassLoader。与静态处理类相比,动态类有诸多好处。

优点:

不需要为真实主题写一个形式上完全一样的封装类,假如主题接口中的方法很多,为每一个接口写一个代理方法也很麻烦。如果接口有变动,则真实主题和代理类都要修改,不利于系统维护;
使用一些动态代理的生成方法甚至可以在运行时制定代理类的执行逻辑,从而大大提升系统的灵活性。

方式:

生成动态代理的方法有很多: JDK中自带动态代理,CGlib, javassist等。这些方法各有优缺点。本文主要探究JDK中的动态代理的使用和源码分析。

动态代理实例:

下面用一个实例讲解一下JDK中动态代理的用法:

public class dynamicProxy implements InvocationHandler {

    private RealSubject = null;

    public Object invoke(Object proxy, Method method, Object[] args){
        if(RealSubject == null) {
            RealSubject = new RealSubject();
        }
        method.invoke(RealSubject, args);
        return RealSubject;
    }

}

客户端代码实例

public class Client {
    public static void main(Strings[] args) {
        Subject subject = (Subject)Proxy.newInstance(ClassLoader.getSystemLoader(), RealSubject.class.getInterfaces(), new DynamicProxy());
        Subject.sayHello();
        Subject.sayGoodBye();
    }
}

从上面的代码可以看出,要利用JDK中的动态代理。利用静态方法Proxy.newInstance(ClassLoader, Interfaces[], InvokeHandler)可以创建一个动态代理类。 newInstance方法有三个参数,分别表示类加载器,一个希望该代理类实现的接口列表,以及实现InvokeHandler接口的实例。 动态代理将每个方法的执行过程则交给了Invoke方法处理。

优点

代理模式能够协调调用者和被调用者,在一定程度上降低了系 统的耦合度。

远程代理使得客户端可以访问在远程机器上的对象,远程机器 可能具有更好的计算性能与处理速度,可以快速响应并处理客户端请求。

虚拟代理通过使用一个小对象来代表一个大对象,可以减少系 统资源的消耗,对系统进行优化并提高运行速度。

保护代理可以控制对真实对象的使用权限。

缺点:

由于在客户端和真实主题之间增加了代理对象,因此 有些类型的代理模式可能会造成请求的处理速度变慢。

实现代理模式需要额外的工作,有些代理模式的实现 非常复杂。

适用环境:

远程(Remote)代理:为一个位于不同的地址空间的对象提供一个本地 的代理对象,这个不同的地址空间可以是在同一台主机中,也可是在 另一台主机中,远程代理又叫做大使(Ambassador)。

虚拟(Virtual)代理:如果需要创建一个资源消耗较大的对象,先创建一个消耗相对较小的对象来表示,真实对象只在需要时才会被真正创建。

Copy-on-Write代理:它是虚拟代理的一种,把复制(克隆)操作延迟 到只有在客户端真正需要时才执行。一般来说,对象的深克隆是一个 开销较大的操作,Copy-on-Write代理可以让这个操作延迟,只有对象被用到的时候才被克隆。

保护(Protect or Access)代理:控制对一个对象的访问,可以给不同的用户提供不同级别的使用权限。

缓冲(Cache)代理:为某一个目标操作的结果提供临时的存储空间,以便多个客户端可以共享这些结果。

防火墙(Firewall)代理:保护目标不让恶意用户接近。

同步化(Synchronization)代理:使几个用户能够同时使用一个对象而没有冲突。

智能引用(Smart Reference)代理:当一个对象被引用时,提供一些额外的操作,如将此对象被调用的次数记录下来等。

我的微信二维码如下,欢迎交流讨论

这里写图片描述

欢迎关注《IT面试题汇总》微信订阅号。每天推送经典面试题和面试心得技巧,都是干货!

微信订阅号二维码如下:

这里写图片描述

参考:
head first 设计模式
http://design-patterns.readthedocs.io/zh_CN/latest/structural_patterns/proxy.html
https://github.com/biezhi/java-bible/blob/master/designpatterns/proxy.md

© 著作权归作者所有

共有 人打赏支持
fengsehng
粉丝 4
博文 284
码字总数 214494
作品 0
朝阳
程序员
编程中的那些套路——关于策略模式

该文章属于《编程中的那些经典套路——设计模式汇总》系列,并且以下内容基于语言PHP 今天讲讲策略模式,策略模式 和工厂模式十分相像(或者说在代码逻辑层面,他们是一样的)。 但策略模式与...

gzchen
08/27
0
0
javascript 设计模式之工厂(Factory)模式

工厂模式介绍 工厂模式是一个创建型的模式,主要就是创建对象。其中工厂模式又分为简单工厂模式和抽象工厂模式。简单工厂模式是通过工厂方法确定创建 对应类型的对象。抽象工厂模式是通过子类...

hlxiong
2014/04/14
0
0
java设计模式-- 单例模式

在很久之前,也就是在大二暑假的时候,那时候看马士兵的视频教程中有提到很多的设计模式。 java的设计模式大致可以分为3大类,23种设计模式。 其中,创建型模式有5种:单例模式、建造者模式、...

爱学习的逃课君
2014/11/27
0
0
代理模式(Proxy Pattern):动态代理 - 最易懂的设计模式解析

前言 今天我来全面总结开发中最常用的设计模式 - 代理模式中的动态代理模式 其他设计模式介绍 1分钟全面了解“设计模式” 单例模式(Singleton) - 最易懂的设计模式解析 简单工厂模式(Sim...

Carson_Ho
04/09
0
0
【设计模式笔记】(十六)- 代理模式

一、简述 代理模式(Proxy Pattern),为其他对象提供一个代理,并由代理对象控制原有对象的引用;也称为委托模式。 其实代理模式无论是在日常开发还是设计模式中,基本随处可见,中介者模式中...

MrTrying
06/24
0
0

没有更多内容

加载失败,请刷新页面

加载更多

Redis常用命令

keys 我把这个命令放在第一位,是因为笔者曾经做过的项目,以及一些朋友的项目,都因为使用keys这个命令,导致出现性能毛刺。这个命令的时间复杂度是O(N),而且redis又是单线程执行,在执行k...

谢思华
38分钟前
2
0
关于css宽度分离

所谓宽度分离就是width 属性不与影响宽度的 padding/border(有时候包括 margin)属性共存 例如: .box{width:200px;padding:20px;border:1px solid;} 为何要做宽度分离 一说到分离就是为了好...

莫西摩西
49分钟前
1
0
Linux常用命令

###############常用命令说明############################## cat /proc/version 显示内核的版本 mv dir1 new_dir 重命名/移动 一个目录 rm -rf a.txt b.txt c.txt 删除多个文件 chmod 777 ......

lyle_luo
56分钟前
3
0
全国地区代码科普

全国地区代码表 天津市 地区代码 地区名称 1100 天津市 辽宁省 地区代码 地区名称 2210 沈阳市 2210 法库县 2210 康平县 2210 辽中县 2210 新民市 2220 大连市 2222 普兰店市 2223 庄河市 22...

恋码之子
56分钟前
1
0
DbForge Schema Compare for MySQL入门教程:生成比较报告

【dbForge Schema Compare for MySQL下载】 当架构比较完成后,您可以生成比较报告以保留架构更改的记录。 1. 在“Comparison” 菜单中,单击“Generate Comparison Report” 。将打开“Gen...

Miss_Hello_World
57分钟前
1
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部