代理模式

代理模式的定义:为其他对象提供一种代理以控制对这个对象的访问。在某些情况下,一个对象不适合或者不能直接引用另一个对象,而代理对象可以在客户端和目标对象之间起到中介的作用。

这里写图片描述

静态代理

简单实例

Subject.java

public interface Subject {
    public void Request();

}

RealSubject.java

public class RealSubject implements Subject{
    @Override
    public void Request() {
        System.out.println("真实的请求");
    }
}

Proxy.java

public class Proxy implements Subject{
    RealSubject realSubject;
    @Override
    public void Request() {
        if(realSubject==null){
            realSubject=new RealSubject();
        }
        realSubject.Request();
    }
}

通过代理实现realSubject的发送请求
Test.java

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

具体实例(追求者通过代理赠送礼物)

SchoolGirl.java

public class SchoolGirl {
    private String name;
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
}

GiveGift.java

public interface GiveGift {
    void giveDolls();
    void giveFlowers();
    void giveChocolate();

}

Pursuit.java

public class Pursuit implements GiveGift{

    public SchoolGirl mm;
    public Pursuit(SchoolGirl mm){
        this.mm=mm;
    }

    @Override
    public void giveDolls() {
        System.out.println(mm.getName()+"送你洋娃娃");
    }

    @Override
    public void giveFlowers() {
        System.out.println(mm.getName()+"送你鲜花");
    }

    @Override
    public void giveChocolate() {
        System.out.println(mm.getName()+"送你巧克力");
    }

}

Proxy.java

public class Proxy implements GiveGift{

    Pursuit gg;
    public Proxy(SchoolGirl mm){
        gg=new Pursuit(mm);
    }

    @Override
    public void giveDolls() {
        gg.giveDolls();
    }

    @Override
    public void giveFlowers() {
        gg.giveFlowers();
    }

    @Override
    public void giveChocolate() {
        gg.giveChocolate();
    }
}

当Pursuit对象无法之间完成giveDolls()、giveFlowers()、giveChocolate()方法时,通过创建代理对象,由代理对象创建new pursuit(),并通过pursuit对象实现方法的调用。

分析:通过这里例子以及扩展我们来看一下静态代理模式的缺点吧:

  • 如果出现上面的需求,那么势必会出现类爆炸的结果;
  • 当然捕捉方法执行时间的代码都一样,我们每个方法都写,每个类都写,这也是代码的重复,没有达到代码复用的效果,这也完全违背了面向对象设计的原则。

思考:防止出现类爆炸,使代码能够得到复用。我们能不能用一个代理类,来代理所有需要的类。

动态代理模式

通过反射机制,利用JDK提供的Proxy类,在程序运行的时候在内存中根据目标对象来创建代理对象,避免了类爆炸的出现。

使用代理模式必须要让代理类和目标类实现相同的接口,客户端通过代理类来调用目标方法,代理类会将所有的方法调用分派到目标对象上反射执行,还可以在分派过程中添加”前置通知”和后置处理(如在调用目标方法前校验权限,在调用完目标方法后打印日志等)等功能。

这里写图片描述

代理类

/**
 * 此类需要实现InvocationHandler接口
 * 调用处理器,当代理对象调用代理方法的时候,注册在调用处理器中的invoke方法会自动调用
 * @author Carl_Hugo
 * @date 2017年5月4日
 */
public class MyInvocationHandler implements InvocationHandler{

    //目标对象,通过反射机制获得
    private Object target;
    //构造方法
    public MyInvocationHandler(Object target) {
        super();
        this.target=target;
    }

    /**
     * 执行目标对象的方法
     * 参数:Object proxy 代理对象的引用,proxy变量中保存代理对象的内存地址
     *      Method method 目标对象的目标方法
     *      Object[] args:目标对象的目标方法执行的时候需要实参
     */
    @Override
    public Object invoke(Object proxy, Method method, Object[] args)
            throws Throwable {
        //开始时间
        long begin = System.currentTimeMillis();
        System.out.println("==============开始==============");
        //执行目标对象中的方法
        Object retValue = method.invoke(target, args);
        //结束时间
        long end = System.currentTimeMillis();
        //计算时间
        System.out.println("==============结束==============");
        System.out.println("耗费时长:"+(end-begin)+"ms");
        return retValue;
    }

    /**
     * 获取目标对象的代理对象
     * @return
     */
    public Object getProxy(){
        return Proxy.newProxyInstance(Thread.currentThread().getContextClassLoader(),
                target.getClass().getInterfaces(), this);
    }

}

测试类

/**
 * 注意:JDK内置的动态代理Proxy只能代理接口
 * (如果既想代理接口又想代理抽象类需要使用第三方组件:例如cglib)
 * @author Carl_Hugo
 * @date 2017年5月4日
 */
public class Test {

    public static void main(String[] args) {
        //实例化目标对象
        UserService userService = new UserServiceImpl();
        //实例化MyInvocationHandler
        MyInvocationHandler invocationHandler = new MyInvocationHandler(userService);
        //根据目标对象创建代理对象
        UserService proxy = (UserService)invocationHandler.getProxy();
        /*UserService proxy = (UserService)Proxy.newProxyInstance(UserService.class.getClassLoader(),
                new Class[]{UserService.class}, invocationHandler);*/
        //执行代理对象的方法
        proxy.add();
    }

}

UserService类

public interface UserService  {

    public abstract void add();

}

UserServiceImpl类

public class UserServiceImpl implements UserService{

    @Override
    public void add() {
        System.out.println("----------add-------------");
    }

}

用起来是很简单吧,其实这里基本上就是AOP的一个简单实现了,在目标对象的方法执行之前和执行之后进行了增强。Spring的AOP实现其实也是用了Proxy和InvocationHandler这两个东西的。

源码:https://github.com/zxiang179/DesignPattern

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值