大话设计模式——代理模式

来源:互联网 发布:Linux解压rar 编辑:程序博客网 时间:2024/06/05 18:45

需求

小明一直暗恋着小花,想了很久,下定决心要向她表白,对她说出我爱你 :)

鉴于笔记整理需要,将原文的故事背景进行改编。

初步实现

  1. 妹子类:

    public class Meizi {    private String name;    public String getName() {        return name;    }    public void setName(String name) {        this.name = name;    }}
  2. 汉子类:

    public class Hanzi {    private Meizi meizi;    public Hanzi(Meizi meizi) {        this.meizi = meizi;    }    public void sayLoveToHer() {        System.out.println("I love you, " + meizi.getName() + "!");    }}
  3. 客户端类:

    public class Client {    public static void main(String[] args) {        Meizi xiaohua = new Meizi();        xiaohua.setName("小花");        Hanzi xiaoming = new Hanzi(xiaohua);        xiaoming.sayLoveToHer();    }}
  4. 运行结果:

    运行结果

分析

大家都知道,现实情况小明很有可能有点害羞,不好意思直接对小花说我爱你。所以,小明想了个办法,决定让小红(小花的闺密)转述,简单来说,小红是个“僚机”。那么,这样的实现方式小红充当一个代理。

代理模式

  • 定义:为其他对象提供一种代理以控制对这个对象的访问。通过引入一个新的对象,来实现对真实对象的操作或者将新的对象作为真实对象的一个替身。即代理对象。

  • 结构示意图:
    结构示意图

代理模式代码实现如下:

  1. Subject类:定义了RealSubject和Proxy的公用接口,这样就可以在任何使用RealSubject的地方使用Proxy;

    public abstract class Subject{    public abstract void request();}
  2. RealSubject类:定义了Proxy所代表的真实实体;

    public class RealSubject extends Subject{    public void request(){        System.out.println("真实的请求");    }}
  3. Proxy类:保存了一个引用使得代理可以访问实体,并提供一个与Subject的接口相同的接口,这种代理就可以用来替代实体;

    public class Proxy extends Subject{    private RealSubject realSubject;    public void request(){        if(realSubject != null)            realSubject = new RealSubject();        realSubject.request();    }}
  4. 客户端代码:

    public class Client {    public static void main(String[] args) {        Proxy proxy = new Proxy();        proxy.request();    }}

再次实现

了解代理模式的实现过程,我们很容易写出运用代理模式的案例实现。小红作为代理对象,代替小明去表白,所以表白是俩者共同的功能接口,小明和小红都要去实现这个功能。

  1. 定义接口:表白

    public interface IExpress {    void sayLoveToHer();}
  2. 汉子实现接口;

    public class Hanzi implements IExpress{    private Meizi meizi;    public Hanzi(Meizi meizi) {        this.meizi = meizi;    }    @Override    public void sayLoveToHer() {        System.out.println("I love you, " + meizi.getName() + "!");    }}
  3. 代理类实现接口;

    public class Proxy implements IExpress {    private Hanzi hanzi;    public Proxy(Hanzi hanzi) {        this.hanzi = hanzi;    }    @Override    public void sayLoveToHer() {        System.out.println("昨天,有个汉子和我说:");        hanzi.sayLoveToHer();    }}
  4. 客户端。

    public class Client {    public static void main(String[] args) {        Meizi xiaohua = new Meizi();        xiaohua.setName("小花");        Proxy xiaohong = new Proxy(new Hanzi(xiaohua));        xiaohong.sayLoveToHer();    }}
  5. 运行结果

    运行结果

再次分析

可能已经发现了,代理对象小红如实的转达了小明的意思,那么如果小明和小红关系很好,可能小红会在小花面前多美言几句,这其实就是代理模式可以增强原本类的功能。例如,在JavaEE中,我们会通过Spring来管理Hibernate的事务,我们并没有去写开启事务、关闭事务的语句,但其实这一切都在背后帮我们做了,我们仅仅需要在Spring的配置文件中去配置好Hibernate的事务管理,其实这背后就是代理模式。

深入代理模式

上面所实现的是一般的静态代理模式,下面介绍一下JDK动态代理:
动态代理和上面静态代理实现区别就是少一个代理类Proxy的实现,而在客户端动态实现功能。

因此,可以看出静态代理在如下情况显得捉襟见肘:

  • 代理对象的一个接口只服务于一种类型的对象,如果要代理的方法很多,势必要为每一种方法都进行代理,静态代理在程序规模稍大时就无法胜任了。
  • 如果接口增加一个方法,除了所有实现类需要实现这个方法外,所有代理类也需要实现此方法。增加了代码维护的复杂度。

JDK动态代理实现

因为创建出来的这个代理类,一定是接口的子类,所以JDK动态代理一定要有接口,并且真实的业务类要实现该接口。

  1. 客户端代码:

    public class Client {    public static void main(String[] args) {        Meizi xiaohua = new Meizi();        xiaohua.setName("小花");        IExpress xiaoming = new Hanzi(xiaohua);        IExpress xiaohong = (IExpress) Proxy.newProxyInstance(xiaoming.getClass().getClassLoader(), xiaoming.getClass().getInterfaces(), new InvocationHandler() {            @Override            public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {                if(method.getName().equals("sayLoveToHer")){                    System.out.println("昨天,小明和我说:");                    Object obj  = method.invoke(xiaoming, args);                    System.out.println("我觉得很不错,答应他吧!");                    return obj;                }                return method.invoke(proxy, args);            }        });        xiaohong.sayLoveToHer();    }}
  2. 运行结果:

    运行结果

最后

动态代理还有Cglib动态代理,在Spring中经常用到。Spring这个框架运用到的设计模式确实非常多,这里推荐前几日掘金上的一篇文章,关于代理模式:JAVA中的静态代理、动态代理以及CGLIB动态代理



个人公众号:每日推荐一片技术博客,坚持每日进步一丢丢…欢迎关注,想建个微信群,主要讨论安卓和Java语言,一起打基础、用框架、学设计模式,菜鸡变菜鸟,菜鸟再起飞,愿意一起努力的话可以公众号留言,谢谢…

原创粉丝点击