设计模式(11)之代理模式

1. 什么是代理模式
Proxy模式又叫做代理模式,是构造型的设计模式之一,它可以为其他对象提供一种代理(Proxy)以控制对这个对象的访问。 所谓代理,是指具有与代理元(被代理的对象)具有相同的接口的类,客户端必须通过代理与被代理的目标类交互,而代理一般在交互的过程中(交互前后),进行某些特别的处理。

2. 代理模式的结构
这里写图片描述

3. 代理模式的角色和职责

subject(抽象主题角色):
真实主题与代理主题的共同接口。

RealSubject(真实主题角色):
定义了代理角色所代表的真实对象。

Proxy(代理主题角色):
含有对真实主题角色的引用,代理角色通常在将客户端调用传递给真实主题对象之前或者之后执行某些操作,而不是单纯返回真实的对象。

下面我举一个 “卖书” 的例子。 首先,该例子中 “卖书”是一个主题觉角色,所以,我们首先定义一个接口(或抽象类)来表示这个主题角色。

//Subject.java

public interface Subject {

    public void sellBook();
}

然后是具体的主题角色,即实现了”卖书”接口的实现类。

//RealSubject.java
public class RealSubject implements Subject{

    public void sellBook() {
        System.out.println("金瓶梅甩卖啦。。。");
    }

}

其实这样,我们就可以”卖书”了,在主方法中,实例化一个RealSubject对象,然后调用sellBook方法就可以实现”卖书”这个功能了。但是,有的时候,为了促销,有时候打折,有时候送代金券,也就是说在”卖书”前后我们还需要做一定的处理的时候,这时候怎么办?将这些操作写到sellBook方法中,显然是不合适的。将这些操作抽取出来一个方法放在RealSubject对象中,好像也不太合适,如果还有其他的RealSubject也实现了Subject接口了呢,那不得再写一遍这些操作?

所以,这里我们再定义一个代理类。

代理类的作用就是在”卖书”这个操作进行之前或之后,我们可以自定义一些自己的操作。这样RealSubject的”卖书”的权利就转交到SubjectProxy这个代理的手中,这个书具体怎么卖,但是核心的sellBook还是调用的RealSubject中的sellBook方法。

言多必失,看代码就一目了然了。

//RealSubjectProxy.java
public class SubjectProxy implements Subject{
    //将RealSubject作为代理的成员变量,因为最终还是要调用RealSubject对象中的sellBook方法的。
    private RealSubject realSubject;

    public void setRealSubject(RealSubject realSubject) {
        this.realSubject = realSubject;
    }

    private void dazhe(){
        System.out.println("买金瓶梅打折.");
    }

    private void give(){
        System.out.println("买金瓶梅送连环画");
    }

    @Override
    public void sellBook() {
        //在真正sellBook前后,我们可以做一些自己的处理。
        dazhe();
        this.realSubject.sellBook();
        give();

    }
}

主类中的代码:

//MainClass.java

public class MainClass {

    public static void main(String[] args) {

        RealSubject realSubject = new RealSubject();
        SubjectProxy proxy = new SubjectProxy();
        proxy.setRealSubject(realSubject);

        proxy.sellBook();
    }
}

4. 动态代理

  1. InvocationHandler 接口
  2. invoke方法
  3. Proxy.newProxyInstance();

什么是动态代理?

前面我们是不是写了一个SubjectProxy这个代理类,该代理类的作用就是在sellBook前后做一些自定义的操作,但是你发现没有,这些个操作都是写在这个代理类中的,如果这些自定义的操作以后需要更改怎么办?去修改SubjectProxy中的代码吗?我咋感觉不太好呢,这扩展性也太差了吧。

所以,聪明的程序员们发明了 动态代理这个东东。

动态代理,我们不需要自己手动实现代理类,即在我们的程序中没有具体的代理类,我们只需要提供自定义的操作即可,在Java中我们只要自定义一个处理类,实现InvocationHandler这个接口,该接口中定义了一个方法,没错,该方法就是实现我们的一些自定义的操作。

现在我们看一下这个自定义事件处理类,RealSubject.java和Subject.java中的代码不变。

//MyHandle.java
package com.zemo.wj;

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

public class MyHandler implements InvocationHandler{
    private RealSubject realSubject;

    public void setRealSubject(RealSubject realSubject) {
        this.realSubject = realSubject;
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args)
            throws Throwable {

        Object result = null;

        dazhe();
        result = method.invoke(realSubject, args);
        give();
        return result;
    }

    private void dazhe(){
        System.out.println("买金瓶梅打折.");
    }

    private void give(){
        System.out.println("买金瓶梅送连环画");
    }
}

在该事件处理类中,实现了InvocationHandler接口中的invoke方法,在该方法中自定义了一些操作。但是,你会法线,他并么有调用RealSubject中的sellBook方法,是的,这里他确实没有调用。想知道为什么吗?我想大概是为了可扩展性吧。

你想想呀,现在Subject中只定义了一个sellBook的方法,改名这个接口又加了一个sellXXX的方法了,如果这个事件处理类中写死了的话,那么Subject这个接口改了,这个事件处理类的代码是不是也要修改,那也太不灵活了吧。所以这里使用了Java中的反射技术。不管你Subject中的接口怎么变,只要你的实现类RealSubject跟着变就是了,我事件处理类最终还不是调用你的实现类RealSubject类中的一个方法就完事了。所以,调用Subject中sellBook方法的操作我们写在客户端比较合适,事件处理类中只包括我们自己要做的处理,这样,只要我们自己的处理不变,那么这个事件处理程序类就不需要做任何改变。

现在我们看一下,主类中的代码:

//MainClass.java

package com.zemo.wj;

import java.lang.reflect.Proxy;

public class MainClass {

    public static void main(String[] args) {

        RealSubject realSubject = new RealSubject();

        MyHandler handler =  new MyHandler();

        handler.setRealSubject(realSubject);

        Subject proxySubject =  (Subject) Proxy.newProxyInstance(RealSubject.class.getClassLoader(), realSubject.getClass().getInterfaces(), handler);
        proxySubject.sellBook();
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值