java设计模式之代理模式(动态代理和静态代理)

代理的含义在于 代替原对象做更多的事情,而不破坏原代码的代码结构。

代理也分静态代理 和 动态代理,我们先以简单的静态代理为例子。

##静态代理:

定义一个接口

package designmode.代理模式;

public interface Sourceable {
	public void method();
}

被代理的对象,它实现了 Sourceable 接口

/**
 * 被代理对象
 * @author panqian
 *
 */
public class Source implements Sourceable {

	@Override
	public void method() {
		System.out.println("the original method!");
	}

}

然后 假设method方法已经不能满足我们的要求,我们需要在这个方法里输出更多的语句,但是我不需要直接修改Source 这个类,我们可以设计一个代理类:

这个代理类Proxy同样实现了Sourceable 接口,但是多了一个Source 成员变量,我们可以通过构造器接收我们原来的对象,然后在代理类的method()方法中,增强我们原有代码的功能(拓展Source对象method的功能 )。

/**
 * Proxy 是一个代理类 静态代理
 *
 * @author panqian
 */
public class Proxy implements Sourceable {

    public Source source;

    public Proxy(Source source) {
        super();
        this.source = source;
    }

    @Override
    public void method() {
        System.out.println("before proxy!");
        source.method();
        System.out.println("after proxy!");
    }

}

最后写一个测试用例并看输出的结果:

public class ProxyTest {
	public static void main(String[] args) {
        Source source = new Source();
        Sourceable sourceable = new Proxy(source);
		sourceable.method();
	}
}

结果:
可以看到,我们达到了我们的目的,不改变原有代码而增强了代码的功能

before proxy!
the original method!
after proxy!

##动态代理

在写代理模式时,我们做的其实是面向接口编程,代理类和被代理类都实现了一个接口,这也是代理的规范写法。在静态代理中,我们自己要编写代理类,虽然没有破坏原有代码,但是也有几个问题
####1.如果我们要做不同接口的代理,而且我们需要增强的功能没有区别的话,重复的编写代理类是 就造成了代码重复。
####2.如果源对象的接口新增了方法,实现类不用多说,就连代理类也需要重新实现新的方法,代码维护难度上升了。

上面问题全出在需要委托代理的类需要跟 代理类一一对应上,jdk给我们的解决方案便是 动态代理。在动态代理中,我们不需要委托类跟代理类一一对应,上面的两个问题 动态代理 来帮我们解决~!

为了展示动态代理的好处,我们在原有接口上新增一个方法:

public interface Sourceable {
	public void method();
	public void method1();
}

Source 类也需要多实现method1()方法:

public class Source implements Sourceable {

    @Override
    public void method() {
        System.out.println("the original method!");
    }

    @Override
    public void method1() {
        System.out.println("the original method1!");
    }

}

关键来了,我们请来了动态代理的核心接口 InvocationHandler,
InvocationHandler 接口只需要实现invoke方法,三个参数依次为 代理对象(基本没什么用),代理对象调用的方法,调用的方法中的参数。通过
method.invoke方法,我们传入需要代理的对象(被代理对象作为DynamicProxy 的成员对象,通过构造器传入),和这个方法的参数,便可以调用被代理对象的原方法。然后其它跟静态代理没什么区别。
还有一点,method.getName()可以知道被代理对象调用了什么方法,根据不同方法可以自由编写增强现有代码的功能。

/**
 * 动态代理,不用自己实现 被代理类
 * Created by panqian on 2017/7/1.
 */
public class DynamicProxy implements InvocationHandler {

    Object object;

    DynamicProxy(Object object) {
        super();
        this.object = object;
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        if ("method1".equals(method.getName())) {
            System.out.println("before dynamicProxy!");
            method.invoke(object, args);
            System.out.println("before dynamicProxy!");
        } else if ("method".equals(method.getName())) {
            System.out.println("before dynamicProxy1!");
            method.invoke(object, args);
            System.out.println("before dynamicProxy1!");
        }
        return null;
    }
}

最后编写测试类

Proxy.newProxyInstance方法传入 被代理对象的classloader,接口和被代理对象本身。它会在代码运行时 自动创建代理对象(免去了自己写代理类的问题),然后通过返回的代理对象调用代理方法。

    public static void main(String[] args) {
        Sourceable source = new Source();

        DynamicProxy dynamicProxy = new DynamicProxy(source);
        Sourceable sourceable = (Sourceable) Proxy.newProxyInstance(Source.class.getClassLoader(), Source.class.getInterfaces(), dynamicProxy);

        sourceable.method();
        System.out.println("=========");
        sourceable.method1();
    }

动态代理 相比较 静态代理 相同点在于都是面向接口编程,都不破坏原有代码而增强功能,不同点在于 动态代理不需要编写大量的代理类,也就免去了很多因为自己写代理类而带来的问题。

在spring大名鼎鼎的aop特性中,Spring提供了两种方式来生成代理对象: JDKProxy和Cglib,默认的策略是如果目标类是接口,则使用JDKProxy,JDKProxy便是我们所说的动态代理,否则使用Cglib来生成代理。所以说代理模式不是空中楼阁,对于减少代码重复量,减少代码冗余有很多实际的用处。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值