软件设计模式第三篇(代理模式)

背景

代理模式是一种常用的设计模式,而对于代理,可根据代理类创建的时间点,分为静态代理和动态代理。

概念

  1. 真实对象:被代理的对象
  2. 代理对象:
  3. 代理模式:代理对象代理真实对象,达到增强真实对象功能的目的

代理类图

在这里插入图片描述
下面我们通过代码帮助大家理解静态代理和动态代理的实现方式

静态解决方案

静态代理

静态代理在程序运行之前,代理类的.class文件已经存在了。静态代理通常只代理一个类,并且要事先知道代理的哪个类。

简单实现
上面讲解了代理的一些基本原理,现在通过简单的例子帮助大家理解,比如张三想购买一台华为手机,如果自己去买价格要5000RMB,如果通过代理公司去买,,由于代理公司进行集中采购,能获得折扣价,价格在4800RMB.

首先,定义购买者接口类Buyer,里面有一个购买的方法 如下

/**
 * @Author: dengcs
 * @Date: 2020/6/24 10:40
 * Comment:购买者接口
 */
public interface Buyer {
	//购买方法
    public void buy();
}

再编写一个购买者实现类ZanBuyer

/**
 * @Author: dengcs
 * @Date: 2020/6/24 10:47
 * Comment:
 */
public class ZanBuyer implements Buyer {
    private String name;
    
    @Override
    public void buy() {
        System.out.println(name+"购买华为手机mate30 pro 5G");    
    }
    
    public ZanBuyer(String name) {
        this.name = name;
    }
}

接着写一个代理公司类ProxyCommy,进行代理

/**
 * @Author: dengcs
 * @Date: 2020/6/24 10:54
 * Comment:
 */
public class ProxyCommy implements Buyer {
    ZanBuyer zanBuyer;

    public ProxyCommy(ZanBuyer zanBuyer) {
        if(zanBuyer.getClass()==ZanBuyer.class) {
            this.zanBuyer = zanBuyer;
        }
    }

    @Override
    public void buy() {
        zanBuyer.buy();
    }
}

代理的代码基本上写完了,下面进行简单的测试,

/**
 * @Author: dengcs
 * @Date: 2020/6/24 10:59
 * Comment: 测试类
 */
public class Test {
    public static void main(String[] args) {
        //被代理对象张三
        Buyer buyer = new ZanBuyer("张三");

        //代理公司,提交被代理对象张三的购买行为
        Buyer proxy = new ProxyCommy( (ZanBuyer) buyer);
        
        //代理公司进行购买
        proxy.buy();
    }
}

测试结果

张三购买华为手机mate30 pro 5G

可以看到,我们先声明了一个被代理对象对象buyer,接着生成代理对象proxy并将buyer 传给了代理对象,最后由代理对象代其完成购买行为,而不是上面的由buyer 直接提交。这就是代理模式。

那么你们会不会觉得奇怪,既然buyer可以直接购买,为什么还要增加一个代理类,这样反而增加了代码量。其实这样做的目的有两个,一是代码解耦,再就是代理对象可以在其中加入其他行为,而不需要修改原有对象的代码。如下,我们做如下代码增强功能

/**
 * @Author: dengcs
 * @Date: 2020/6/24 10:54
 * Comment:
 */
public class ProxyCommy implements Buyer {
    ZanBuyer zanBuyer;

    public ProxyCommy(ZanBuyer zanBuyer) {
        if(zanBuyer.getClass()==ZanBuyer.class) {
            this.zanBuyer = zanBuyer;
        }
    }


    @Override
    public void buy() {
        zanBuyer.buy();
        System.out.println("团体采购,价格更优惠!");
    }
}

测试结果为
在这里插入图片描述
可以看到,我们只在代理类中帮张三购买手机后,执行其他操作,便实现了我们想要的功能,并没有去修改我们原有的ZanBuyer类中的代码。这种操作也是使用代理模式的一个很大的优点。

动态解决方案

如果Buyer除了购买手机外,还能购买汽车等其它行为呢,这就需要用到动态代理方式了,对Buyer进行如下改造

/**
 * @Author: dengcs
 * @Date: 2020/6/24 10:40
 * Comment:购买接口
 */
public interface Buyer {
    public void buy();
    public void buyCar();
}

ZanBuyer的改造

/**
 * @Author: dengcs
 * @Date: 2020/6/24 10:47
 * Comment:
 */
public class ZanBuyer implements Buyer {
    private String name;


    @Override
    public void buy() {
        System.out.println(name+"购买华为手机mate30 pro 5G");
    }

    public ZanBuyer(String name) {
        this.name = name;
    }

    @Override
    public void buyCar() {
        System.out.println(name+"购买一台比亚迪新能源汽车-汉");
    }
}

把静态代理类ProxyCommy 改成 动态代理类DynProxy


import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;

/**
 * @Author: dengcs
 * @Date: 2020/6/24 10:54
 * Comment:动态代理DynProxy
 */
public class DynProxy {

    //设计一个类变量记住代理类要代理的目标对象
    private Buyer buyer;// = new ZanBuyer("张三");

    public DynProxy(Buyer buyer) {
        this.buyer = buyer;
    }

    /**
     * 设计一个方法生成代理对象
     * @Method: getProxy
     * @Description: 这个方法返回Buyer的代理对象:Buyer buyer = LiuDeHuaProxy.getProxy();//得到一个代理对象
     * @return 某个对象的代理对象
     */
    public Buyer getProxy(){
           return (Buyer) Proxy.newProxyInstance(DynProxy.class.getClassLoader(), buyer.getClass().getInterfaces(), new InvocationHandler() {

                   /**
                    * InvocationHandler接口只定义了一个invoke方法,因此对于这样的接口,我们不用单独去定义一个类来实现该接口,
                    * 而是直接使用一个匿名内部类来实现该接口,new InvocationHandler() {}就是针对InvocationHandler接口的匿名实现类
                    */
                   /**
                    * 在invoke方法编码指定返回的代理对象干的工作
                    * proxy : 把代理对象自己传递进来
                    * method:把代理对象当前调用的方法传递进来
                    * args:把方法参数传递进来
                    *
                    * 当调用代理对象的person.sing("冰雨");或者 person.dance("江南style");方法时,
                    * 实际上执行的都是invoke方法里面的代码,
                    * 因此我们可以在invoke方法中使用method.getName()就可以知道当前调用的是代理对象的哪个方法
                    */
                @Override
                public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                    //如果调用的是代理对象的buy方法
                    if (method.getName().equals("buy")) {
                        System.out.println("这里是代理购买手机的");
                        return method.invoke(buyer, args); //代理对象调用真实目标对象的buy方法去处理用户请求
                    }
                    //如果调用的是代理对象的buyCar方法
                    if (method.getName().equals("buyCar")) {
                        System.out.println("这里是代理购买汽车的");
                        return method.invoke(buyer, args);//代理对象调用真实目标对象的buyCar方法去处理用户请求
                    }
                    return null;
                }
        });
    }

}

测试Test 如下改造

/**
 * @Author: dengcs
 * @Date: 2020/6/24 10:59
 * Comment: 测试类
 */
public class Test {
    public static void main(String[] args) {

/*
        //1、静态代理
        //被代理对象张三
        Buyer buyer = new ZanBuyer("张三");

        //代理公司,提交被代理对象张三的购买行为
        Buyer proxy = new ProxyCommy( (ZanBuyer) buyer);

        //代理公司进行购买
        proxy.buy();
*/

        //2、动态代理
        Buyer buyer1 = new DynProxy(new ZanBuyer("张三")).getProxy(); //获得代理对象
        buyer1.buy(); //代理买手机

        buyer1.buyCar();//代理买汽车

    }
}

运行结果如下
在这里插入图片描述
至此,静态代理、动态代理基本讲完了。。

总结

其实代理模式最主要的就是有公共接口,一个代理类,代理类持有具体类的实例,代为执行具体类的实例方法。

  1. 代理模式其优点在于:代理模式实现使用者与真实处理者的分离,降低系统的耦合度;调用接口时,便于扩展一些业务无关的其他操作,不影响原系统。

  2. 缺点在于:增加类代理角色,性能上比直接使用低。

代码下载地址Demo

想了解更多设计模式,请关注我吧_

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
<<引用:设计模式是描述了软件开发中常见问题的解决方案的一种模板化设计原则。设计模式主要用于解决软件设计中的重复性问题,帮助开发人员更高效地编写可维护、可扩展的代码。设计模式有很多种,如工厂模式、单例模式、观察者模式等等。>> 对于你的问题,关于Java设计模式第3章的课后习题参考答案,很抱歉,我无法提供特定章节的课后习题参考答案,因为我没有访问特定书籍的权限。但是,我可以为你提供一些常见的Java设计模式及其原则的信息,希望能帮到你。 常见的Java设计模式包括但不限于: 1. 创建型模式:单例模式、工厂模式、抽象工厂模式、建造者模式、原型模式。 2. 结构型模式:适配器模式、桥接模式、装饰者模式、组合模式、外观模式、享元模式代理模式。 3. 行为型模式:策略模式、模板方法模式、观察者模式、迭代器模式、责任链模式、命令模式、备忘录模式、状态模式、访问者模式、中介者模式、解释器模式。 这些设计模式都有各自的原则和含义,如创建型模式用于对象的创建和实例化,结构型模式用于类和对象的组合,行为型模式用于对象之间的通信和交互等等。每种设计模式都有其适用的场景和优缺点,具体使用哪种设计模式需要根据实际需求来确定。 希望以上信息对你有所帮助。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值