⑦ 设计模式的艺术-13.代理(Proxy)模式
为什么需要代理模式
- 中介隔离作用:在某些情况下,一个客户类不想或者不能直接引用一个委托对象,而代理类对象可以在客户类和委托对象之间起到中介的作用,其特征是代理类和委托类实现相同的接口。
- 开闭原则,增加功能:代理类除了是客户类和委托类的中介之外,我们还可以通过给代理类增加额外的功能来扩展委托类的功能,这样做我们只需要修改代理类而不需要再修改委托类,符合代码设计的开闭原则。代理类主要负责为委托类预处理消息、过滤消息、把消息转发给委托类,以及事后对返回结果的处理等。代理类本身并不真正实现服务,而是同过调用委托类的相关方法,来提供特定的服务。真正的业务功能还是由委托类来实现,但是可以在业务功能执行的前后加入一些公共的服务。例如我们想给项目加入缓存、日志这些功能,我们就可以使用代理类来完成,而没必要打开已经封装好的委托类。
核心作用:
• 通过代理,控制对对象的访问!
可以详细控制访问某个(某类)对象的方法,在调用这个方法前做前置处理,调用这个方法后
做后置处理。(即:AOP的微观实现!)
– AOP(Aspect Oriented Programming面向切面编程)的核心实现机制!
什么是代理模式?
代理模式的定义:代理模式给某一个对象提供一个代理对象,并由代理对象控制对原对象的引用。通俗的来讲代理模式就是我们生活中常见的中介。
有哪几种代理模式?
我们有多种不同的方式来实现代理。如果按照代理创建的时期来进行分类的话, 可以分为两种:静态代理、动态代理。
静态代理是由程序员创建或特定工具自动生成源代码,在对其编译。在程序员运行之前,代理类.class文件就已经被创建了。
动态代理是在程序运行时通过反射机制动态创建的。
代理模式 为真实对象提供一个代理, 从而控制对真实对象的访问 。
静态代理

代理模式包含如下角色:
Subject:抽象主题角色。可以是接口,也可以是抽象类。
RealSubject:真实主题角色。业务逻辑的具体执行者。
ProxySubject:代理主题角色。内部含有RealSubject的引用,负责对真实角色的调用,并在真实主题角色处理前后做预处理和善后工作。
代理模式优点:
职责清晰 真实角色只需关注业务逻辑的实现,非业务逻辑部分,后期通过代理类完成即可。
高扩展性 不管真实角色如何变化,由于接口是固定的,代理类无需做任何改动。
代码示例

•抽象角色
定义代理角色和真实角色的公共对外方法
•真实角色
实现抽象角色,定义真实角色所要实现的业务逻辑,供代理角色调用。
关注真正的业务逻辑!
•代理角色
实现抽象角色,是真实角色的代理,通过真实角色的业务逻辑方法来实现抽象方法,并可以附加自己的操作。
将统一的流程控制放到代理角色中处理!
Star
package com.cnki.proxy.dynamicProxy;
public interface Star {
/**
* 面谈--代理人去做
*/
void confer();
/**
* 签合同--代理人去做
*/
void signContract();
/**
* 订票--代理人去做
*/
void bookTicket();
/**
* 唱歌--本人去做
*/
void sing();
/**
* 收钱--代理人去做
*/
void collectMoney();
}
RealStar
package com.cnki.proxy.dynamicProxy;
public class RealStar implements Star {
@Override
public void bookTicket() {
System.out.println("RealStar.bookTicket()");
}
@Override
public void collectMoney() {
System.out.println("RealStar.collectMoney()");
}
@Override
public void confer() {
System.out.println("RealStar.confer()");
}
@Override
public void signContract() {
System.out.println("RealStar.signContract()");
}
@Override
public void sing() {
System.out.println("RealStar(周杰伦本人).sing()");
}
}
ProxyStar
package com.cnki.proxy.dynamicProxy;
public class ProxyStar implements Star {
private Star star;
public ProxyStar(Star star) {
super();
this.star = star;
}
@Override
public void bookTicket() {
System.out.println("ProxyStar.bookTicket()");
}
@Override
public void collectMoney() {
System.out.println("ProxyStar.collectMoney()");
}
@Override
public void confer() {
System.out.println("ProxyStar.confer()");
}
@Override
public void signContract() {
System.out.println("ProxyStar.signContract()");
}
@Override
public void sing() {
star.sing();
}
}
测试
package com.cnki.proxy.dynamicProxy;
public class Client {
public static void main(String[] args) {
Star real = new RealStar();
Star proxy = new ProxyStar(real);
proxy.confer();
proxy.signContract();
proxy.bookTicket();
proxy.sing();
proxy.collectMoney();
}
}

应用场景
– 安全代理:屏蔽对真实角色的直接访问。
– 远程代理:通过代理类处理远程方法调用(RMI)
– 延迟加载:先加载轻量级的代理对象,真正需要再加载真实对象。
• 比如你要开发一个大文档查看软件,大文档中有大的图片,有可能一个图片有100MB,在打开文件时不可能将所有的图片都显示出来,这样就可以使用代理模式,当需要查看图片时,用proxy来进行大图片的打开。
动态代理
动态代理相比于静态代理的优点:抽象角色中(接口)声明的所以方法都被转移到调用处理器一个集中的方法中处理,这样,我们可以更加灵活和统一的处理众多的方法。
JDK自带的动态代理
java.lang.reflect.Proxy
作用:动态生成代理类和对象
java.lang.reflect.InvocationHandler(处理器接口)
可以通过invoke方法实现对真实角色的代理访问
每次通过Proxy生成代理类对象对象时都要指定对应的处理器对象
Star
package com.cnki.proxy.dynamicProxy;
public interface Star {
/**
* 面谈
*/
void confer();
/**
* 签合同
*/
void signContract();
/**
* 订票
*/
void bookTicket();
/**
* 唱歌
*/
void sing();
/**
* 收钱
*/
void collectMoney();
}
RealStar
package com.cnki.proxy.dynamicProxy;
public class RealStar implements Star {
@Override
public void bookTicket() {
System.out.println("RealStar.bookTicket()");
}
@Override
public void collectMoney() {
System.out.println("RealStar.collectMoney()");
}
@Override
public void confer() {
System.out.println("RealStar.confer()");
}
@Override
public void signContract() {
System.out.println("RealStar.signContract()");
}
@Override
public void sing() {
System.out.println("RealStar(周杰伦本人).sing()");
}
}
StarHandler
package com.cnki.proxy.dynamicProxy; import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method; public class StarHandler implements InvocationHandler { Star realStar; public StarHandler(Star realStar) {
super();
this.realStar = realStar;
} @Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
Object object = null; System.out.println("真正的方法执行前!");
System.out.println("面谈,签合同,预付款,订机票"); if(method.getName().equals("sing")){
object = method.invoke(realStar, args);
} System.out.println("真正的方法执行后!");
System.out.println("收尾款");
return object;
} }
测试
package com.cnki.proxy.dynamicProxy;
import java.lang.reflect.Proxy;
public class Client {
public static void main(String[] args) {
Star realStar = new RealStar();
StarHandler handler = new StarHandler(realStar);
Star proxy = (Star) Proxy.newProxyInstance(ClassLoader.getSystemClassLoader(), new Class[]{Star.class}, handler);
proxy.sing();
}
}

开发框架中应用场景
struts2中拦截器的实现
数据库连接池关闭处理
Hibernate中延时加载的实现
mybatis中实现拦截器插件
AspectJ的实现
spring中AOP的实现
日志拦截
声明式事务处理
web service
RMI远程方法调用
⑦ 设计模式的艺术-13.代理(Proxy)模式的更多相关文章
- 设计模式C++描述----13.代理(Proxy)模式
一. 举例说明 我们有时打开一个网站时会发现有这样的现象,网站上的文字都显示出来了,但是上面的图片还没显示,要等一会才能显示. 这些未打开的图片的位置上,还是会有图片框和一些等待的信息的,这就是代理模 ...
- Head First 设计模式 —— 13. 代理 (Proxy) 模式
思考题 如何设计一个支持远程方法调用的系统?你要怎样才能让开发人员不用写太多代码?让远程调用看起来像本地调用一样,毫无瑕疵? P435 已经接触过 RPC 了,所以就很容易知道具体流程:客户端调用目标 ...
- 设计模式的征途—13.代理(Proxy)模式
所谓代购,简单说来就是找人帮忙购买所需要的商品.代购分为两种类型,一种是因为在当地买不到某件商品,又或者是因为当地这件商品的价格比其他地区的贵,因此托人在其他地区甚至国外购买该商品,然后通过快递发货或 ...
- 《图解设计模式》读书笔记9-2 Proxy模式
目录 Proxy模式 示例程序 程序描述 类图 程序 角色和类图 角色 模式类图 思路拓展 提升速度 代理与委托 Http代理 与其他模式的关联 Decorator模式 Proxy模式 Proxy是代 ...
- 代理(Proxy)模式简介
Proxy 模式简介 代理模式的两个应用: 打开文档时加载大图片 例如:如果有个对象是一张很大的图片,而这张图片需要花费很长时间才能显示出来,那么当这个图片包含在文档中的后面时,使用编辑器或浏览器打开 ...
- 设计模式之(三)Proxy模式
今天学习Proxy模式.代理模式是在对已有对象操作困难或者不太方便时,选择用代理的方式对对象进行访问.Proxy实现的方法必须和被代理对象一致. 举一个简单的例子, 有一个Math类实现了IMath接 ...
- 设计模式(二十一)Proxy模式
在面向对象编程中,“本人”和“代理人”都是对象.如果“本人”对象太忙了,有些工作无法自己亲自完成,就将其交给“代理人”对象负责. 示例程序的类图. 示例程序的时序图.从这个时序图可以看出,直到调用pr ...
- 设计模式--代理(Proxy)模式
在公司,经常性听到采购部的人说采购某样东材料,采购不了,需要通过代理商才可以.以前Insus.NET也做有一个练习<找人办事,代理设计模式(Proxy)>http://www.cnblog ...
- 十、设计模式之代理(Proxy)模式
什么是代理模式 代理模式是对象的结构模式,为其他对象提供一种对象以控制对这个对象的访问. 代理模式的结构图如下:(源自大话设计模式) Subject:定义了RealSubject和Proxy的公共 ...
随机推荐
- 软工实践-Alpha 冲刺 (10/10)
队名:起床一起肝活队 组长博客:博客链接 作业博客:班级博客本次作业的链接 组员情况 组员1(队长):白晨曦 过去两天完成了哪些任务 描述: 完成所有界面的链接,整理与测试 展示GitHub当日代码/ ...
- C++ Primer Plus学习:第十章
过程性编程和面向对象编程 面向对象编程(OOP)的特性: 抽象 封装和数据隐藏 多态 继承 代码的可重用性 抽象和类 类是一种将抽象转化为用户定义类型的C++工具,它将数据表示和操纵数据的方法合成一个 ...
- C++对象模型 多重继承与虚函数表
一 多重继承 1) 代码: Code#include <iostream>using namespace std; class B1{public: int x; virtua ...
- larave5.6 引入自定义函数库时,报错不能重复定义
方法一:使用function_exists判断 方法二:使用命名空间 namespace test; function test(){ echo 'test/test'; } namespace te ...
- 第167天:canvas绘制柱状图
canvas绘制柱状图 1.HTML <!DOCTYPE html> <html lang="en"> <head> <meta char ...
- HDU4790_Just Random
这个题目我只能说我一看就知道是这么做的,但是由于实现能力略水,Wa了3发. 题意为给你两个区间[a,b]和[c,d],两个区间分别任取一个数,现在要你求出这个数模p的值为m的概率有多大. 其实是这么做 ...
- Appium与Robotium区别
Appium是基于UIAutomator框架实现的.Appium测试进程与目标应用进程是分开的,所以Appium不能直接访问目标应用的各种element属性进行copy&paste,而只能模拟 ...
- python 序列化 pickle shelve json configparser
1. 什么是序列化 我们把变量从内存中变成可存储或传输的过程称之为序列化. 序列化之后,就可以把序列化后的内容写入磁盘,或者通过网络传输到别的机器上. 反过来,把变量内容从序列化的对象重新读到内存里称 ...
- debug - vue中通过ajax获取数据时,如何避免绑定的数据中出现property of undefined错误
因为获取服务器是异步的,所以 vue 先绑定数据. 如果 ??? 是通过 ajax 异步获取的,在获取之前,???是未定义的.此时在外面的标签上添加一个 v-if="???" 可以 ...
- [Violet]蒲公英 分块
发现写算法专题老是写不动,,,, 所以就先把我在luogu上的题解搬过来吧! 题目大意:查询区间众数,无修改,强制在线 乍一看是一道恐怖的题,仔细一看发现并没有那么难: 大致思路是这样的,首先我们要充 ...