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

需求

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

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

初步实现

  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语言,一起打基础、用框架、学设计模式,菜鸡变菜鸟,菜鸟再起飞,愿意一起努力的话可以公众号留言,谢谢…

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值