设计模式(七)——代理模式

本文属于系列文章《设计模式》,附上文集链接

代理模式

  • 定义:为其他对象提供一种代理以控制对这个对象的访问(原话是:Provide asurrogate or placeholder foranother object to control access to it. )
  • 写这篇文章的时候,因为已经把书都看过了,所以有点搞不清代理模式和装饰器模式的区别。但是现在一看定义就很清楚明了了,提供代理,以控制对这个对象的访问,看到黑体加粗的控制没,这才是代理模式的精髓。(因为没有这个控制的话,和装饰器模式没太大区别)
  • 属于行为类模式
  • 分类:静态代理,动态代理

举个例子

首先要明确一件事,设计模式的提出一定是为了解决某一些共性的,在编码上遇到的问题。重点字是控制,所以举一个要访问对象,要被另外的东西来控制的例子。比如我很喜欢彭于晏,我很想让彭于晏帮我签个名,但是我不能直接找到彭于晏,要找他的经纪人(代理)来帮忙,就来模仿这个吧。没用到代理模式

// 彭于晏
public class Eddie {
    private Eddie() {   }
    // 单例,叫彭于晏的有很多,拍Vivo广告的只有一个
    private final static Eddie eddie = new Eddie();
    private AgentOfEddie eddieAgent;
    public void sign(AgentOfEddie eddieAgent) {
        if (eddieAgent == this.eddieAgent) {
            System.out.println(this.getClass().getSimpleName() + ":VivoX9柔光双摄,照亮你的美");
        } else {
            System.out.println("这不是我的经纪人,我不签");
        }
    }
    // 提供经纪人的获取途径,毕竟经纪人也是确定的
    public AgentOfEddie getAgentOfEddie() {
        eddieAgent = new AgentOfEddie(this);
        return eddieAgent;
    }
    public static Eddie getEddie() {
        return eddie;
    }
}
// 彭于晏的经纪人
public class AgentOfEddie {
    public AgentOfEddie(Eddie eddie){
        this.eddie = eddie;
    }
    private Eddie eddie;
    // 让杰伦哥签名
    public void getEddieSign(){
        eddie.sign(this);
    }
}
// 场景类1
public class Cilent {
    public static void main(String[] args) {
        Eddie eddie = Eddie.getEddie();
        AgentOfEddie agentOfEddie = eddie.getAgentOfEddie();
        agentOfEddie.getEddieSign();
    }
}
结果:
Eddie:VivoX9柔光双摄,照亮你的美
// 场景类2,直接new一个经纪人来签名
public class Cilent {
    public static void main(String[] args) {
        Eddie eddie = Eddie.getEddie();
        AgentOfEddie agentOfEddie = new AgentOfEddie(eddie);
        agentOfEddie.getEddieSign();
    }
}
结果:
这不是我的经纪人,我不签
// 场景类3,直接让彭于晏签名
public class Cilent {
    public static void main(String[] args) {
        Eddie eddie = Eddie.getEddie();
        eddie.sign(new AgentOfEddie(eddie));
    }
}
结果:
这不是我的经纪人,我不签

代码的意思就是,只有通过Eddie获取到的经纪人去sign,才可以让彭于晏来签名,除此之外,无论是自己new的经纪人去sign还是直接用eddie执行sign,都不能获取到签名。
看起来并无毛病,还完美实现,打出三秒的控制效果。确实,写这个例子的时候我都有点怀疑代理模式是用来干嘛的这种感觉。对嘛,看书上说,比如在现实生活中,打官司找律师,就是为了避免官司的种种是是非非,只需要做好自己的答辩就行了
用上面的代码来讲,就是彭于晏可以不用处理对外的事情,交给经纪人就行了,那也没毛病啊,上面的代码还是可以用的,经纪人那里加控制不就行了吗?而且也符合定义提供一种代理以控制对这个对象的访问。(对的,这里的重点针对的是,为什么代理模式要用接口来实现?这个接口是必要的吗?看过代理模式的应该会懂的。我上面就没用接口,而且也实现了,所以我就没想明白)
让我想清楚的,是Spring 的aop编程,aop是面向切面编程,而这个切面,通俗点来讲就是一个个的方法,那么spring是如何做到可以对每一个方法都实行切面控制的呢(虽说是动态代理)?嘿嘿,是不是有点头绪了。
回到上面的代码,假设彭于晏不止要签名,还要拍Vivo的广告,还要拍益达的广告,还要拍湄公河行动,这些都是要和外面商量的,需要经纪人来控制的,这么做会造成什么问题?彭于晏每多一个对外的行动,经纪人都要多一个对外的行动,生活上是这样的,但放在上面的代码,经纪人对着彭于晏的对外行动一个一个添加方法!!!可怕吧。

用代理模式要怎么做呢?静态代理例子

// 定义明星接口
public interface Celebrity {
    // 签名
    public void sign(Celebrity celebrity);
    // 拍广告
    public void makeAdvertising(Celebrity celebrity);
}
// 实现明星接口的彭于晏
public class Eddie implements Celebrity{
    private Eddie() {   }
    // 单例,叫彭于晏的有很多,拍Vivo广告的只有一个
    private final static Eddie eddie = new Eddie();
    private AgentOfEddie eddieAgent;
    // 提供经纪人的获取途径,毕竟经纪人也是确定的
    public AgentOfEddie getAgentOfEddie() {
        eddieAgent = new AgentOfEddie(this);
        return eddieAgent;
    }
    public static Eddie getEddie() {
        return eddie;
    }
    // 签名
    @Override
    public void sign(Celebrity celebrity) {
        if (celebrity == this.eddieAgent) {
            System.out.println(this.getClass().getSimpleName() + ":VivoX9柔光双摄,照亮你的美");
        } else {
            System.out.println("这不是我的经纪人,我不签");
        }
    }
    // 拍广告
    @Override
    public void makeAdvertising(Celebrity celebrity) {
        if (celebrity == this.eddieAgent) {
            System.out.println(this.getClass().getSimpleName() + "在拍广告:VivoX9柔光双摄,照亮你的美");
        } else {
            System.out.println("这不是我的经纪人,我不拍");
        }
    }
}
// 实现明星接口的彭于晏的经纪人
public class AgentOfEddie implements Celebrity{
    public AgentOfEddie(Eddie eddie){
        this.eddie = eddie;
    }
    private Eddie eddie;
    // 让彭于晏签名
    @Override
    public void sign(Celebrity celebrity) {
        // TODO Auto-generated method stub
        eddie.sign(celebrity);
    }
    @Override
    public void makeAdvertising(Celebrity celebrity) {
        eddie.makeAdvertising(celebrity);
    }
}
// 场景类1
public class Cilent {
    public static void main(String[] args) {
        Eddie eddie = Eddie.getEddie();
        AgentOfEddie agentOfEddie = eddie.getAgentOfEddie();
        agentOfEddie.sign(agentOfEddie);
        agentOfEddie.makeAdvertising(agentOfEddie);
    }
}
结果:
Eddie:VivoX9柔光双摄,照亮你的美
Eddie在拍广告:VivoX9柔光双摄,照亮你的美
// 场景类2,直接new一个经纪人来执行签名这件事
public class Cilent {
    public static void main(String[] args) {
        Eddie eddie = Eddie.getEddie();
        AgentOfEddie agentOfEddie = new AgentOfEddie(eddie);
        agentOfEddie.sign(agentOfEddie);
        agentOfEddie.makeAdvertising(agentOfEddie);
    }
}
结果:
这不是我的经纪人,我不签
这不是我的经纪人,我不拍
// 场景类3,直接让彭于晏签名
public class Cilent {
    public static void main(String[] args) {
        Eddie eddie = Eddie.getEddie();
        eddie.sign(new AgentOfEddie(eddie));
    }
}
结果:
这不是我的经纪人,我不签
这不是我的经纪人,我不拍

分析下代码,首先规定了一个接口Celebrity,用来规定明星应该具有的行为,接着,Eddie类实现该接口,AgentOfEddie类也实现该接口,同时,在AgentOfEddie中声明了Eddie,接口的方法实现就用<code>Eddie</code>的方法来实现。规定接口方法的一个好处是,确保代理类(AgentOfEddie)的方法和被代理类(Eddie)的主体方法是一致的,场景类也执行无误。而上面的这种代理模式,具体一点又叫做强制代理(如果有看其他博客,应该知道还有普通代理等很多具体的代理方法的,还有JDK动态代理,cglib动态代理,这里就不举例子了,因为还没那个实力╮(╯▽╰)╭)。

代理模式最常用的地方,就是实现对另一个对象的控制,比如说我们J2EE的拦截器,就是代理模式活生生的应用,在被拦截对象的方法的执行前后进行事务控制。当然还有很多应用地方的,慢慢探讨吧。

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

推荐阅读更多精彩内容

  • 代理模式(Proxy Pattern):构建了透明置于两个不同对象之内的一个对象,从而能够截取或代理这两个对象间的...
    刀斧手何在阅读 1,005评论 1 1
  • Spring Cloud为开发人员提供了快速构建分布式系统中一些常见模式的工具(例如配置管理,服务发现,断路器,智...
    卡卡罗2017阅读 134,601评论 18 139
  • 1. Java基础部分 基础部分的顺序:基本语法,类相关的语法,内部类的语法,继承相关的语法,异常的语法,线程的语...
    子非鱼_t_阅读 31,587评论 18 399
  • 事例 小张是一个普普通通的码农,每天勤勤恳恳地码代码。某天中午小张刚要去吃饭,一个电话打到了他的手机上。“是XX公...
    余平的余_余平的平阅读 493评论 0 0
  • 洛洛突然收到了一条微信,上边写着你不生气了吧?是我不好,我太差劲了,你值得更好的人。千万不要对爱情丧失信心啊。 看...
    杨咩咩YY阅读 654评论 13 1