二十三种设计模式之代理模式

今天来一起探讨下GOF二十三种设计模式的代理模式。

代理模式是一种结构型设计模式,也是设计模式中较为重要的一种,原因在于代理模式(动态代理)可以自动帮我们的类增强功能,并且很多框架底层大量使用了代理模式,例如Spring的AOP等。

在讲代理模式前,我有必要提一下代理和委托。相信大家看了很多网上代理模式的博客都会拿中介,黄牛买票作为例子吧。其实,房屋中介严格意义来讲不属于代理。

上面是来自法律快车对于代理和委派的区别,指出了代理和委派的根本区别是是否对客户是透明的。

举个例子,大家用黄牛买票的时候你知不知道这票其实不是黄牛的,而是黄牛通过一些渠道购买铁路局的; 大家租房子的时候知不知道这房子不是中介的,而是房东的? 答案是:是

那么既然知道,所以这种中介的行为只能说是委派,而不是代理!

那么怎样的场景是代理呢?比如 同样是相亲的场景,但是仔细思考:

小红回家过年被家里安排相亲,但是小红不太愿意去于是小红找到特别要好的闺蜜小王,让小王代替小红去相亲,然后顺便给自己汇报下如何再决定是否交往。

结果某某天,小红的闺蜜就代替小红去相亲了,到了约定的地点,见到相亲对象小明,于是说,小明你好,我是"小红” ………………,对于小明而言他当然不知道今天这个来相亲的其实不是小红!

所以这个小王就充当了小红的代理角色。

从例子中我们可以看到 代理模式的几个重要角色:

小红--> 目标对象 、 小王-->代理对象

由于代理对象是以被代理对象的名义做事情,所以代理对象和目标对象必须实现相同的接口,保持行为的一致性。

下看下类图

ps:Java真的是很面向对象!^_^

上代码:

public interface IProxy {
    void blindDate();
}


public class XiaoHong implements IProxy {
    
    @Override
    public void blindDate() {
        System.out.println("我需要相亲");
    }
}

public class XiaoHongProxy implements IProxy{
    private IProxy iProxy;

    public XiaoHongProxy(IProxy iProxy) {
        this.iProxy = iProxy;
    }

    @Override
    public void blindDate() {
        System.out.println("好的,我会帮你去应付");
        iProxy.blindDate();
        System.out.println("回来了,对方可以建议交往");
    }
}


//客户端代码
public class XiaoMing {

    public static void main(String[] args) {

        //对于小明而言,他不知道来相亲的是谁,只能是人家说是谁就是谁
        IProxy xiaoHong = new XiaoHongProxy(new XiaoHong());

        /**
         *
         *其实这里不是对xiaoHong调用,而是xiaoHong的闺蜜调用,
         * 只是这些对于xiaoMing是透明的
         */
        xiaoHong.blindDate();
    }
}

这样就实现了简单的代理模式,但是小红可以找自己的闺蜜帮忙,那要是其他人也有这种需求怎么办,小王只会帮组自己的闺蜜。

所以其他人只能找自己的兄弟帮忙咯~  

这就是静态代理,只能给指定的类增强功能,在实际开发中比如我们要给项目中所有的类增加一个日志功能,我们不可能给每个类都去写一个代理类,那估计程序员要疯掉。

但是又有这种需求,所以我们就需要使用动态代理来解决这个问题。

动态代理即在程序运行期间,动态的给目标类生成一个代理类,前提是这个目标类必须是实现了某个接口(JDK动态代理要求),这样就能获得一个增强功能的代理类出来

上代码:

public interface IProxy {
    void blindDate();
}


public class Person implements IProxy{


    @Override
    public void blindDate() {
        System.out.println("近期有一个相亲");
    }
}


public class ProxyFactory {

    private IProxy iProxy;

    public ProxyFactory(IProxy iProxy) {
        this.iProxy = iProxy;
    }


    public IProxy createProxy() {
        return (IProxy) Proxy.newProxyInstance(iProxy.getClass().getClassLoader(),
                iProxy.getClass().getInterfaces(),
                new InvocationHandler() {
                    @Override
                    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {

                        System.out.println("明白需求,前往去帮助应付相亲");
                        Object invoke = method.invoke(iProxy, args);
                        System.out.println("对方很丑,不建议交往");
                        return invoke;
                    }
                }
        );
    }
}



//客户端
public class Client {

    public static void main(String[] args) throws Exception {

        ProxyFactory proxyFactory = new ProxyFactory(new Person());
        IProxy zhangSan = proxyFactory.createProxy();

        zhangSan.blindDate();
    }
}

上述是利用JDK自带的Proxy类实现的动态代理,其原理就是利用字节码重组,在程序运行期间生成一个类,这个类实现了目标类的接口。

代码中利用匿名内部类实现的接口InvocationHandler 中有一个invoke()方法,其实这个调用的就是目标类的方法,

因为代理类和目标类实现了同一个接口,所以代理类中也会有这个方法,我们通过在invoke()方法上下添加代码,已达到增强目标类功能的目的。

除了使用JDK原生的方式实现动态代理也可以用cglib来实现,这里就不展开了。

看到动态代理实现我们也清楚了动态代理的使用场景,

动态代理主要是将与业务不相关的与主业务分离出来,达到解耦的目的,同时给类增强功能。动态代理大量使用在框架底层,所以掌握动态代理对于我们对Spring源码学习有很大帮助。

好了,以上就是今天所要分享的,码字不易多多支持~ ^_^

 

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值