23种设计模式:04代理模式与动态代理模式

代理模式

代理模式思想非常简单,为其他对象提供一种代理以控制对这个对象的访问。下面我举一个漫威中的英雄“钢铁侠”的例子,在战斗中钢铁侠的外盔甲帮托尼打架。

UML图

在这里插入图片描述

代码

  • 接口,我这里举例的是漫威公司
interface  Marvel{
    void fly();
    void guard();
    void shooting();
}
  • 托尼,本来是平凡人,因为继承了漫威的接口,然后有了钢铁外壳,称为了钢铁侠
class Musk implements Marvel{

    @Override
    public void fly() {
        System.out.println("控制机器");
    }

    @Override
    public void guard() {
        System.out.println("控制机器");
    }

    @Override
    public void shooting() {
        System.out.println("控制机器");
    }
}
  • 钢铁侠的外壳
class IronMan implements Marvel{
    private Marvel marvel;
    public IronMan(Marvel marvel){
        this.marvel = marvel;
    }

    @Override
    public void fly() {
        marvel.fly();
        System.out.println("钢铁侠飞起来了");
    }

    @Override
    public void guard() {
        marvel.guard();
        System.out.println("钢铁侠抵御了共计");
    }

    @Override
    public void shooting() {
        marvel.shooting();
        System.out.println("钢铁侠向敌人做了射击!!");
    }
}
  • main方法中调用吧!
    public static void main(String[] args) {
        Marvel marvel = new IronMan(new Musk());
        marvel.fly();
        marvel.guard();
        marvel.shooting();
    }

应用场景

远程代理

以前我们2个项目之间希望有业务交流,就可以是使用webservice技术,而webservice就是远程代理。这样可以为一个对象在不同的地址空间提供局部代表。这样可以隐藏一个对象在不同地址空间。

虚拟代理

如果创建一个对象需要花费很长的时间,我们可以使用代理模式,先创建一个代理对象,系统可以立即返回,而后台我们采用异步的方式创建真实的的对象,比如Android中,我们可以使用代理模式去异步加载图片。

安全代理

我们可以通过调用代理模式,而非真实对象,从而对访问者做权限验证

智能代理

比如我们需要统计一个类被调用的次数,我们可以直接调用代理类,然后再代理类中做调用统计。

总结

例子可能不是非常恰当,但思想没问题,代理模式也很简单,他可以在不改变原来逻辑代码的情况下,为对象添加新的功能,满足设计模式的“开放 - 封闭”原则,另外今天主要讲的是动态代理。

动态代理

动态代理使用很简单,原理方面本打算细说,但原理涉及到反射相关的知识,由于篇幅过长就不深入讲解了,如果以后有空,我会单独写一篇关于动态代理原理方面的博客,下面,我先抛出一个问题,再使用动态代理解决。

抛出问题思考

下面有3个类,分别是你好、再见、寒暄
此时,我希望在每次say()方法调用的前面加上加上“打开麦克风”、在调用完say()方法的后面加上“关闭麦克风”。而nothing()方法就什么也不做。

interface SayInterface {
    void say();

    void nothing();
}
class Hello implements SayInterface {
    @Override
    public void say() {
        System.out.println("Hello bridge!");
    }

    @Override
    public void nothing() {
        System.out.println("Hello Nothing");
    }
}
class ByeBye implements SayInterface {

    @Override
    public void say() {
        System.out.println("ByeBye Bridge");
    }
    @Override
    public void nothing() {
        System.out.println("ByeBye Nothing");
    }
}
class Ask implements SayInterface {

    @Override
    public void say() {
        System.out.println("How are you!");
    }

    @Override
    public void nothing() {
        System.out.println("Ask Nothing");
    }
}
  • 调用的方法如下,ProxyXXXX表示能创建你需要的代理类的工具
        Hello hello = new Hello();
        SayInterface proxySay = (SayInterface) ProxyXXXX.createProxy(hello);//此时我希望创建一个代理类
        proxySay.say();
        proxySay.nothing();

此时,你可以思考1分钟,如果不使用代理模式,你应该怎样完成ProxyXXXX类

动态代理解决

根据上面的问题,你是否发现,你需要写3个代理类,而且3个代理类的方法都非常相识,如果我们将3个代理类,换成100个类,你将写100个,维护将痛苦不堪……
所以,我们希望写一个能代理各种类的代理类,前提是被代理的类的需要的代理服务都一样。好吧,下面看看动态代理是什么样子吧!

  • 下面是能创建代理类的Hander
class ProxyHandler implements InvocationHandler {
    private Object target;

    /*
    这里就可以返回你需要的代理类
     */
    public Object createProxy(Object target){
        this.target = target;
        return Proxy.newProxyInstance(target.getClass().getClassLoader(), target.getClass().getInterfaces(),this);
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        if(method.getName().equals("say")){
            System.out.println("打开麦克风");
            method.invoke(target, args);
            System.out.println("关闭麦克风");
        } else {
            method.invoke(target, args);
        }
        return null;
    }
}
  • 代码调用如下:
        Hello hello = new Hello();
        ProxyHandler handler = new ProxyHandler();
        SayInterface proxySay = (SayInterface) handler.createProxy(hello);//此时我希望你能创建一个Hello的代理类
        proxySay.say();
        proxySay.nothing();
  • 打印如下
打开麦克风
Hello bridge!
关闭麦克风
Hello Nothing

是不是如此神奇的事情就发生了,到底ProxyHandler是什么,为啥这么强大,因为它借助了java的反射功能。下面我们就简单介绍一下ProxyHandler吧!

理解ProxyHandler

  • ProxyHandler中神奇的就是createProxy方法了,而createProxy其实就下面这个代码
Proxy.newProxyInstance(ClassLoader loader,
                 Class<?>[] interfaces,
                 InvocationHandler h)
  • 它根据ClassLoader和接口,就能创建一个代理类,而这个代理的每个方法的具体实现,还得借助于InvocationHandler接口。InvocationHandler接口是由一个抽象方法,如下:
    public Object invoke(Object proxy, Method method, Object[] args)
        throws Throwable;
  • invoke就是反射中对方法的实现,所以,你在main方法中,每调用一次代理类的方法,其实都是调用的invoke(),所以,代理的业务逻辑都再invoke()方法中。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值