设计模式之——代理模式(Proxy)

代理模式

代理模式(Proxy) 的定义:由于某些原因需要给某对象提供一个代理以控制对该对象的访问。这时,访问对象不适合或者不能直接引用目标对象,代理对象作为访问对象和目标对象之间的中介。

        简单地说就是我们实际访问目标是通过代理对象来间接访问的,代理就是对目标方法进行增强

静态代理

定义

        静态代理是我们自己创建的类,在编译时就已经将接口、本代理类和代理类确定下来。

软件设计模式中所指的代理一般就是说的静态代理。

代码讲解

        老规矩模拟个情景: 微商代购。

  1. 首先抽象一个动作接口Action,我们的动作是买buy()
interface Action {
    void buy();
}
  1. 在没有代购前,我们自己去买东西,需要自己去挑选,然后买,再自己带回来。用程序实现:
public class Main implements Action {
    @Override
    public void buy() {
        System.out.println("to buy...");
    }
    public static void main(String[] args) {
        System.out.println("selecting...");
        new Main().buy();
        System.out.println("bring back...");
    }
}

运行结果:结果1

        这是最简单且常见的编程方式,我们下面通过微商来代替我们去买:

  1. 创业建一个微商,他也实现Action接口。微商有在我们付账前的准备工作before(),和在我们下单后的动作after(),其内容是代替我们亲自去做的动作,我们这里直接使用Action对象方法:
public class Proxy implements Action{
    Action a;
    public Proxy(Action a) { this.a = a;}
    public void before() {
        System.out.println("proxy to select...");
    }
    public void after() {
        System.out.println("proxy to buy...");
        System.out.println("proxy to send...");
    }
    @Override
    public void buy() {
        before();
        a.buy();
        after();
    }
}
  1. 我们只需要付账pay()就好了,注意在调用代理Proxy对象需要把我们被代理的对象传进去:
public class Main implements Action {
    @Override
    public void buy() {
       pay();
    }
    public void pay() {
        System.out.println("to pay");
    }
    public static void main(String[] args) {
        Proxy p = new Proxy(new Main());
        p.buy();
        System.out.println("get it");
    }
}

运行结果:结果2

        通过上述代码,我们就已经完成一个简单的静态代理模式了。当然我们可以把情景想的更现实,比如微商上面还有地区代理,只需要再写一个代理对象让他嵌套代理就可以。

特点

        我们在创建代理对象时,通过构造器塞入一个目标对象,然后在代理对象的方法内部调用目标对象同名方法,并在调用前后做增强逻辑。也就是说,代理对象 = 增强代码 + 目标对象。有了代理对象后,就不用原对象了。

缺点:

        开发者需要手动为目标类编写对应的代理类,而且要对类中的每个方法都编写增强逻辑的代码,如果当前系统中已经存在成百上千个类,工作量太大了,且重复代码过多。该怎么解决呢?这就用到了动态代理。

动态代理

定义

        动态代理就是在静态代理的基础上创建代理对象更加的灵活,动态代理类的字节码在程序运行时,由Java反射机制动态产生。它会根据需要,通过反射机制在程序运行期,动态的为目标对象创建代理对象,无需程序员手动编写它的源代码。

代码讲解

        动态代理中要用到JDK的反射组件java.lang.reflect,还是使用上面的例子进行代码讲解。

  1. 首先给微商代理类对象改名为ProxyShop与Java反射中的Proxy区分开:
  2. 改写主程序,使用reflect组件中的Proxy.newProxyInstance()方法,其中第一个参数是被代理类,第二个参数是使用到的接口类,第三个参数有就是实现调用处理程序的内部类:
public class Main implements Action {
    @Override
    public void buy() {
        pay();
    }
    public void pay() {
        System.out.println("to pay");
    }
    public static void main(String[] args) {
        Main m = new Main();
        Action a = (Action) Proxy.newProxyInstance(Main.class.getClassLoader(),
                new Class[]{Action.class},
                new InvocationHandler() {
                    @Override
                    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                        System.out.println(method.getName() + " start: ");
                        Object o = method.invoke(m, args);
                        System.out.println(method.getName() + " end!");
                        return o;
                    }
                });
        a.buy();
        System.out.println("get it");
    }
}

运行结果:结果3

        实际上jajdk动态代理在生成的动态代理类$Proxy0.class中,构造方法调用了父类Proxy.class的构造方法,给成员变量invocationHandler赋值,$Proxy0.classstatic模块中创建了被代理类的方法,调用相应方法时方法体中调用了父类中的成员变量InvocationHandlerinvoke()方法。

动态代理机制及特点

  • 通过实现InvocationHandler接口创建自己的调用处理器;

  • 通过为Proxy类指定ClassLoader对象和一组interface来创建动态代理类;

  • 通过反射机制获得动态代理类的构造函数,其唯一参数类型是调用处理器接口类型;

  • 通过构造函数创建动态代理类实例,构造时调用处理器对象作为参数被传入。

其他实现

注意:JDK的动态代理要依靠接口实现,如果有些类并没有接口实现,则不能使用JDK代理。、

        JDK的动态代理存在一些局限性,java还可以实现别的动态代理方法:

  • CGLIB

        Enhancer对象调用setSuperclass()方法设置父类,调用setCallback()方法设置回调,回调中的对象实现MethodInterceptor接口,最后生成ceate()动态代理对象。

  • Instrument

        通过类加载过程中修改二进制字节码的方式进行动态代理实现。

  • 结合springAOP
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值