在上海乐字节学习的第四十天(持续更新中)

你知道设计模式中的代理模式吗?

代理模式在 java 开发中是一种比较常见的设计模式。设计目的在为服务类与客户类之间插入其他功能,插入的功能对于调用者是透明的,起到伪装控制的作用,如租房的例子房客、中介、房东。对于代理模式中即:客户类、代理类、委托类(被代理类)。

代理模式的两个设计原则:

1.代理类与委托类具有相似的行为(共同)

2.代理类增强委托类的行为

Uml简图如下:

代理模式实现的方式

  • 静态代理

  • 动态代理

案例实操

静态代理

为某个对象提供一个代理,代理角色固定,以控制对这个对象的访问。代理类和委托类有共同的父类和父接口,这样在任何使用委托类对象的地方都可以用代理对象代替。代理类负责请求的预处理、过滤、将请求分派给委托类处理、以及委托类执行完请求后的后续处理。

<pre spellcheck="false" class="md-fences md-end-block ty-contain-cm modeLoaded" lang="java" contenteditable="false" cid="n19" mdtype="fences" style="box-sizing: border-box; overflow: visible; font-family: var(--monospace); font-size: 0.9rem; display: block; break-inside: avoid; text-align: left; white-space: normal; background-image: inherit; background-position: inherit; background-size: inherit; background-repeat: inherit; background-attachment: inherit; background-origin: inherit; background-clip: inherit; background-color: rgb(255, 255, 255); position: relative !important; width: inherit; color: rgb(51, 51, 51); font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration-style: initial; text-decoration-color: initial;">/**

  • 接口 抽象角色
  • 定义行为
    */
    public interface Marry {
    public void toMarry();
    }</pre>

<pre spellcheck="false" class="md-fences md-end-block ty-contain-cm modeLoaded" lang="java" contenteditable="false" cid="n20" mdtype="fences" style="box-sizing: border-box; overflow: visible; font-family: var(--monospace); font-size: 0.9rem; display: block; break-inside: avoid; text-align: left; white-space: normal; background-image: inherit; background-position: inherit; background-size: inherit; background-repeat: inherit; background-attachment: inherit; background-origin: inherit; background-clip: inherit; background-color: rgb(255, 255, 255); position: relative !important; width: inherit; color: rgb(51, 51, 51); font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration-style: initial; text-decoration-color: initial;">/**

  • 目标类 真实角色
    */
    public class You implements Marry{
    @Override
    public void toMarry() {
    System.out.println("等了这么久,终于等到你。。。 ");
    }
    }</pre>

<pre spellcheck="false" class="md-fences md-end-block ty-contain-cm modeLoaded" lang="java" contenteditable="false" cid="n21" mdtype="fences" style="box-sizing: border-box; overflow: visible; font-family: var(--monospace); font-size: 0.9rem; display: block; break-inside: avoid; text-align: left; white-space: normal; background-image: inherit; background-position: inherit; background-size: inherit; background-repeat: inherit; background-attachment: inherit; background-origin: inherit; background-clip: inherit; background-color: rgb(255, 255, 255); position: relative !important; width: inherit; color: rgb(51, 51, 51); font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration-style: initial; text-decoration-color: initial;">/**

  • 代理类 代理角色
  • 1.与目标角色实现共同接口
  • 2.持有目标类的引用
  • 3.增强目标角色行为
    */
    public class MarryCompany implements Marry{
    // 目标角色引用
    private Marry target;
    public MarryCompany(Marry target) {
    this.target = target;
    }
    public void before(){
    System.out.println("婚礼现场紧张布置中......");
    }
    @Override
    public void toMarry() {
    before();
    target.toMarry();
    after();
    }
    public void after(){
    System.out.println("恭喜您成功进入人生第二阶段.....");
    }
    }</pre>

<pre spellcheck="false" class="md-fences md-end-block ty-contain-cm modeLoaded" lang="java" contenteditable="false" cid="n22" mdtype="fences" style="box-sizing: border-box; overflow: visible; font-family: var(--monospace); font-size: 0.9rem; display: block; break-inside: avoid; text-align: left; white-space: normal; background-image: inherit; background-position: inherit; background-size: inherit; background-repeat: inherit; background-attachment: inherit; background-origin: inherit; background-clip: inherit; background-color: rgb(255, 255, 255); position: relative !important; width: inherit; color: rgb(51, 51, 51); font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration-style: initial; text-decoration-color: initial;">public class Test {
public static void main(String[] args) {
// 构造代理角色同时传入真实角色
MarryCompany marryCompany=new MarryCompany(new You());
marryCompany.toMarry();
}
}</pre>

因为静态代理对于代理的角色是固定的,如 dao 层 20 个 dao 类,如果要对方法的访问权限进行代理,此时需要创建 20 个静态代理角色,引起类爆炸,无法满足生产上的需要,于是就催生了动态代理的思想。

动态代理

相比于静态代理,动态代理在创建代理对象上更加的灵活,它会根据需要通过反射机制在程序运行期动态的为目标对象创建代理对象,代理的行为可以代理多个方法, 即满足生产需要的同时又达到代码通用的目的。动态代理的两种实现方式:

jdk 实现动态代理

对于 jdk 动态代理实现方式比较复杂,回调方式实现底层原理参考: http://rejoy.iteye.com/blog/1627405

<pre spellcheck="false" class="md-fences md-end-block ty-contain-cm modeLoaded" lang="java" contenteditable="false" cid="n28" mdtype="fences" style="box-sizing: border-box; overflow: visible; font-family: var(--monospace); font-size: 0.9rem; display: block; break-inside: avoid; text-align: left; white-space: normal; background-image: inherit; background-position: inherit; background-size: inherit; background-repeat: inherit; background-attachment: inherit; background-origin: inherit; background-clip: inherit; background-color: rgb(255, 255, 255); position: relative !important; width: inherit; color: rgb(51, 51, 51); font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration-style: initial; text-decoration-color: initial;">import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
/**
jdk 动态代理
/
public class JdkHandler implements InvocationHandler{
// 目标类
private Object target;
public JdkHandler(Object target) {
this.target = target;
}
/

  • 程序运行期动态创建代理角色
  • @return
    /
    public Object getProxy(){
    /
    *
  • 获取代理对象
  • 1.类加载器
  • 2.目标类 实现的接口数组
  • 3.当前类
  • @return
    */
    return Proxy.newProxyInstance(this.getClass().getClassLoader(),
    target.getClass().getInterfaces(),
    this);
    }
    public void before(){
    System.out.println("婚礼现场紧张布置中......");
    }
    @Override//InvocationHandler内部参数 当前目标类的方法 参数
    public Object invoke(Object proxy, Method method, Object[] args)throws Throwable {
    before();//增强真实角色行为
    Object result= method.invoke(target, args);// 执行真实角色方法
    after();//增强真实角色行为
    return result;
    }
    public void after(){
    System.out.println("恭喜您成功进入人生第二阶段.....");
    }
    }</pre>

cglib 动态代理实现(了解)

code generator library ,操作字节码。 与 jdk 提供的代理区别,Proxy:委托类必须有接口,制作过程比较快,执行慢;cglib:委托类可以没有接口,继承的思维来实现相似性,制作代理过程比较慢,执行快。主要解决没有接口类的代理实现。

<pre spellcheck="false" class="md-fences md-end-block ty-contain-cm modeLoaded" lang="xml" contenteditable="false" cid="n31" mdtype="fences" style="box-sizing: border-box; overflow: visible; font-family: var(--monospace); font-size: 0.9rem; display: block; break-inside: avoid; text-align: left; white-space: normal; background-image: inherit; background-position: inherit; background-size: inherit; background-repeat: inherit; background-attachment: inherit; background-origin: inherit; background-clip: inherit; background-color: rgb(255, 255, 255); position: relative !important; width: inherit; color: rgb(51, 51, 51); font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration-style: initial; text-decoration-color: initial;"><dependency>
<groupId>cglib</groupId>
<artifactId>cglib</artifactId>
<version>2.2.2</version>
</dependency></pre>

<pre spellcheck="false" class="md-fences md-end-block ty-contain-cm modeLoaded" lang="java" contenteditable="false" cid="n32" mdtype="fences" style="box-sizing: border-box; overflow: visible; font-family: var(--monospace); font-size: 0.9rem; display: block; break-inside: avoid; text-align: left; white-space: normal; background-image: inherit; background-position: inherit; background-size: inherit; background-repeat: inherit; background-attachment: inherit; background-origin: inherit; background-clip: inherit; background-color: rgb(255, 255, 255); position: relative !important; width: inherit; color: rgb(51, 51, 51); font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration-style: initial; text-decoration-color: initial;">import java.lang.reflect.Method;
import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;
public class CglibInterceptor implements MethodInterceptor {
private Object target;
public CglibInterceptor(Object target) {
this.target = target;
}
// 运行期动态创建代理类
public Object getProxy(){
Enhancer enhancer=new Enhancer();
//设置父类 class
enhancer.setSuperclass(target.getClass());
//设置回调对象实现接口的类
enhancer.setCallback(this);
return enhancer.create();
}
public void before(){
System.out.println("婚礼现场紧张布置中......");
}
@Override
public Object intercept(Object arg0, Method arg1, Object[] arg2,MethodProxy arg3) throws Throwable {
before();//增强真实角色行为
Object result= arg3.invoke(target, arg2);
after();//增强真实角色行为
return result;
}
public void after(){
System.out.println("恭喜您成功进入人生第二阶段.....");
}
}</pre>

扩展

UML表示的相关规则

“可见性”表示该属性对类外的元素是否可见,包括公有(Public)、私有(Private)、受保护(Protected)和朋友(Friendly)4 种,

在类图中分别用符号+、-、#、~表示 。

UML 中的类图有以下几种关系:

依赖关系(带箭头虚线)、

关联关系(带X个箭头的实线)、

聚合关系(带空心菱形的实线)、

组合关系(带实心菱形的实线)、

泛化关系(带空心三角箭头的实线)、

实现关系(带空心三角箭头的虚线)、

其中泛化和实现的耦合度相等,它们是最强的。

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 194,088评论 5 459
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 81,715评论 2 371
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 141,361评论 0 319
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 52,099评论 1 263
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 60,987评论 4 355
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 46,063评论 1 272
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 36,486评论 3 381
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 35,175评论 0 253
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 39,440评论 1 290
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 34,518评论 2 309
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 36,305评论 1 326
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,190评论 3 312
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 37,550评论 3 298
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 28,880评论 0 17
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,152评论 1 250
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 41,451评论 2 341
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 40,637评论 2 335

推荐阅读更多精彩内容