十一、代理模式 —专注,做最好的自己!#和设计模式一起旅行#

专注,把更多的时间放到提示自己核心竞争能力上面来!其他的事情交给别人去做吧。

故事背景

我和设计模式MM开的奶茶店火了,一个是设计模式MM长的好看,波涛汹涌,还有一个是我们的饮品的确好喝,并且还特别在乎用户的体验,上一篇的模板方法模式中,我们最后的例子就询问顾客是否要加入调味料,而不是强制加入。

俗话说,人怕出名,猪怕壮!

出名后好多的媒体想让我参加他们的节目说一下我这个创业的过程和对这次创业的看法(做演讲)。一个媒体还好说,我可以轻松搞定从前期到后期一系列的时间安排,可是现在好多媒体以及各种饮品活动邀请(做宣传),面对这么的应酬活动我头大了。

此时设计模式MM说要代替我做将一部分工作,当我的代理人,但是也不能代替我做全部的事情。

在面向对象编程中,“本人”和“代理人”都是对象。如果“本人”太忙了,有些工作如法自己亲自完成,就将其交给“代理人”负责。

故事主角

代理模式:给某个对象提供一个代理或占位符,并由代理对象来控制对原对象的访问。

代理模式类图

  • Subject(抽象主题角色):申明了真实主题和代理主题的共同接口。
  • Proxy(代理人):包含了对真实主题的引用,从而可以在任何时候操作真实的主题对象。代理主题和真实主题实现一个相同的接口。
  • RealSubject(真实的主题):定义了代理角色所代表的真实对象,实现了真实的业务操作。
  • Client(请求者):Client本身并不包含在代理模式中。

简单代理实现:

interface Subject{
    void request();
}

public class RealSubjcet implements Subject {
    @Override
    public void request() {
        //do something
    }
}

public class ProxySubjcet implements Subject {

    private Subject subject;
    public ProxySubjcet(Subject subject){
        this.subject = subject;
    }
    @Override
    public void request() {
        //proxy do somethind
        subject.request();//real request
        //proxy do somethind
    }
}

public class Client {

    public static void main(String[] args) {
        Subject subject = new ProxySubjcet(new RealSubjcet());

        subject.request();
    }
}

武功修炼 - 静态代理

下面来看设计模式MM如果成我的代理的:

public interface WorkSubject {

    void doSpeech();
}
public class RealMe implements WorkSubject {
    @Override
    public void doSpeech() {
        System.out.println("我专心做演讲就可以了......");
    }
}

public class ProxyPatternMM implements WorkSubject {
    private WorkSubject workSubject;

    public ProxyPatternMM(WorkSubject workSubject) {
        this.workSubject = workSubject;
    }
    @Override
    public void doSpeech() {
        System.out.println("设计模式MM帮助我对接活动和安排活动时间");
        workSubject.doSpeech();
        System.out.println("设计模式MM帮助我处理活动的一些事情");
    }
}


public class Client {

    public static void main(String[] args) {
        WorkSubject workSubject = new ProxyPatternMM(new RealMe());

        workSubject.doSpeech();
    }
}


设计模式MM帮助我对接活动和安排活动时间
我专心做演讲就可以了......
设计模式MM帮助我处理活动的一些事情

上面这个是静态代理,因为要给代理只能代理一个接口服务,如果现在有多个接口的话,那么则肯定代理累就很多了,所有的代理除了调用方法不一样ia,其他操作都一样,则此时肯定会有重复的代码。

武功修炼 - 动态代理-使用InvocationHandler

注:这部分使用到了Java的反射。

使用到InvocationHandler和Proxy。

public interface InvocationHandler { Object invoke(Object var1, Method var2, Object[] var3) throws Throwable; }
参数说明:

- Object proxy : 被代理的对象
- Method method : 要代理的方法 - Object args[] : 方法调用时所需要的参数

此时我们可以实现InvocationHandler 定义我们自己的Handler:

// MyInvocationHandler 代理的最终操作类
public class MyInvocationHandler implements InvocationHandler {
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {


        return null;
    }
}

在实现MyInvocationHandler 中的invoke方法前,在介绍一下Proxy类。

Proxy类
Proxy类是专门完成代理的操作类,可以通过此类为一个或多个接口动态的生成实现类,此类提供了如下操作方法:

public static Object newProxyInstance(ClassLoader loader,
                                          Class<?>[] interfaces,
                                          InvocationHandler h)

参数说明:
- ClassLoaer loader:类加载器 - Class<?> interfaces : 得到全部的接口 - InvocationHandler h: 得到InvocationHandler接口的子类实例
public class RealMe implements WorkSubject {
    @Override
    public void doSpeech() {
        System.out.println("我做演讲开始了......");
        try {
            Thread.sleep(5000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("我做演讲结束了......");

    }
}

// MyInvocationHandler 代理的最终操作类
public class MyInvocationHandler implements InvocationHandler {

     private Object obj;

    public Object newInstance(Object obj){
        this.obj = obj;//真实的主题类
        return Proxy.newProxyInstance(obj.getClass().getClassLoader(),obj.getClass().getInterfaces(),this);
    }
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        long startTime = System.currentTimeMillis();
        System.out.println("代理为我开始做的事情");//记录日志。记录访问时间
        Object temp = method.invoke(this.obj,args);
        System.out.println("代理为我结束做的事情");//计算访问时间
        long endTime = System.currentTimeMillis();
        System.out.println("一场doSpeech总过要花费的时间 : " + (endTime-startTime)/1000 + "秒");
        return temp;
    }
}


public class Client {

    public static void main(String[] args) {
        WorkSubject workSubject = (WorkSubject)new MyInvocationHandler()
        .newInstance(new RealMe());

        workSubject.doSpeech();
    }
}


代理为我开始做的事情
我做演讲开始了......
我做演讲结束了......
代理为我结束做的事情
一场doSpeech总过要花费的时间 : 5

此时当还有其他的事情需要代理,那么只使用这个一个代理就可以搞定了!
要代理的对象如果配置在配置文件中,那么就可以进行被代理的对象的动态变化了,也不需要修改代码了。

武功深入 - Spring 代理模式

在Spring 中有一中编码规范,叫面向切面编程(AOP),AOP是面向系统特定点的一种编程,如事务处理,日志记录,异常抛出等,AOP允许在执行这些特定点方法的之前或者之后进行补充动作,如何实现这种操作呢?Spring使用的代理模式进行操作的。

更多的代理模式

  1. 远程代理(Remote Proxy):为一个位于不同的地址空间的对象提供一个本地的代理对象,这个不同的地址空间可以是在同一台主机中,也可是在另一台主机中,远程代理又称为大使(Ambassador)。

  2. 虚拟代理(Virtual Proxy):如果需要创建一个资源消耗较大的对象,先创建一个消耗相对较小的对象来表示,真实对象只在需要时才会被真正创建。

  3. 保护代理(Protect Proxy/Access Proxy):控制对一个对象的访问,可以给不同的用户提供不同级别的使用权限。

  4. 缓冲代理(Cache Proxy):为某一个目标操作的结果提供临时的存储空间,以便多个客户端可以共享这些结果。

  5. 智能引用代理(Smart Reference Proxy):当一个对象被引用时,提供一些额外的操作,例如将对象被调用的次数记录下来等。

总结

  1. 使用代理人提升出来速度!比如,在开始的设计模式MM作为我的代理的时候,有活动需要我出场,假如出场费没有给到10块,那么设计模式MM就会拒绝这次活动,我就不会收到去做演讲的消息。
  2. 代理和委托:代理的对象只能解决他能解决的问题,如果遇到问题解决不了,那么就会“转交”给主题对象去解决,“转交”实际上就是一种委托。
  3. 代理模式透明性,Client 不用去在意究竟调用的ProxySubject还是RealSubject。
Next 期待下一篇吧!在巴厘岛的奶茶店搞了这么久,还是要继续旅行啊!把奶茶店盘出去,继续上路,去英国剑桥,感受一下康桥的魅力!下一篇:适配器模式——解决手机充电的烦恼。

参考


如果您觉得这篇博文对你有帮助,请点赞或者喜欢,让更多的人看到,谢谢!

如果帅气(美丽)、睿智(聪颖),和我一样简单善良的你看到本篇博文中存在问题,请指出,我虚心接受你让我成长的批评,谢谢阅读!
祝你今天开心愉快!


欢迎访问我的csdn博客,我们一同成长!

不管做什么,只要坚持下去就会看到不一样!在路上,不卑不亢!

博客首页 : http://blog.csdn.net/u010648555

相关文章
相关标签/搜索