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

作者: l_sivan | 来源:发表于2017-03-31 16:16 被阅读102次

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

    代理模式

    • 定义:为其他对象提供一种代理以控制对这个对象的访问(原话是: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的拦截器,就是代理模式活生生的应用,在被拦截对象的方法的执行前后进行事务控制。当然还有很多应用地方的,慢慢探讨吧。

    水平有限,难免有错,还请评论区指责下

    相关文章

      网友评论

        本文标题:设计模式(七)——代理模式

        本文链接:https://www.haomeiwen.com/subject/ucuuottx.html