Java 设计模式(七)代理模式

一、简介

代理模式可以为实际对象创建一个代理,在对象的方法调用时,代理模式可以在方法调用前添加前置处理(比如权限验证),在结果返回前添加结果处理(比如加密),可以添加异常处理等等。。。总之用途十分广泛,java也为此提供了支持。

二、代码示例

要求:
1、设计一个人类,初始化姓名,拥有外出和回家两个方法;
2、通过代理模式为外出方法添加前置处理:出门前检查手机钱包;
3、通过代理模式为回家方法添加后置处理:回家后结算当日开销;

通知接口(定义前置、后置方法)、人类接口(定义行为):

//人类接口
public interface IPeople {
    //外出
    void goOut();
    //回家
    void goHome();
}
//前置、后置方法接口定义
public interface IAdvice {
    void before();
    void after();
}

IAdvice 接口的命名是应用时常用的命名方式,可自行修改,后文中以“通知”代表该接口。另外常用的通知方法还有处理异常和处理结果等,可自行添加。

人类及通知的简单实现:

//人类实现类
public class PeopleImpl implements IPeople {
    private String name;
    //初始化姓名
    public PeopleImpl(String name) {
        this.name = name;
    }
    @Override
    //外出方法
    public void goOut() {
        System.out.println(name+" 要外出了...");
    }
    @Override
    //回家方法
    public void goHome() {
        System.out.println(name+" 回家了...");
    }
}
//通知简单实现
public class CheckAdvice implements IAdvice {
    @Override
    //出门之前
    public void before() {
        System.out.println("before---检查手机钱包是否带齐...");
    }
    @Override
    //回家之后
    public void after() {
        System.out.println("after---结算今日开销");
    }
}

这里通知和行为的不同实现就是代理模式中代理行为的体现,在后续需要进行新的前后置处理、结果处理等只需要实现通知接口即可。现在有了具体实现类以及对行为的前后置处理,最后就需要将通知植入到行为中(即Handler),java内置支持动态代理,创建handler需要实现 InvocationHandler 接口。

Handler实现类

public class ScheduleHandler implements InvocationHandler {
    private IAdvice advice;
    private Object target;
    //handler需要持有目标对象和一个通知才能实现植入
    public ScheduleHandler(Object target,IAdvice advice) {
        this.advice = advice;
        this.target = targefat;
    }
    @Override
    //方法执行
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        //存储方法执行的返回值,方法无返回值则返回空
        Object result = null;
        //执行目标对象的外出方法前执行前置处理
        if(method.getName().equals("goOut")){
            advice.before();
            result = method.invoke(target, args);
        }
        //执行目标对象的回家方法后执行后置处理
        else if(method.getName().equals("goHome")){
            result = method.invoke(target, args);
            advice.after();
        }
        return result;
    }
}

这里实现了通知植入及方法执行,但不同的方法名会对应一个 if…else… 从设计的角度看这显然是不合理的,假如下次增加了新的行为如吃午餐,则这里又需要添加 if…else… 语句,所以可以写一个方法执行器统一管理方法行为,虽然看起来是将 if…else… 搬到了另一个类中,但是当你有多个 Handler 需要维护时,这将节省不少工作。比如多加一个Handler,他将在开销结算后对结果进行处理:藏一部分私房钱(原Handler需要保留,毕竟不是每一个人都藏私房钱),那我们只要在方法执行器中添加新的方法处理即可,而不用修改两个Handler。

场景模拟:

public class ProxyTest {
    public static void main(String[] args) {
        //创建Tom
        IPeople tom = new PeopleImpl("Tom");
        //准备创建代理需要的参数
        Class<?> clazz = tom.getClass();
        Class<?>[] interfaces = clazz.getInterfaces();
        ScheduleHandler hander = new ScheduleHandler(tom, new CheckAdvice());
        //创建代理对象(注意:第一个参数是类加载器)
        IPeople tomProxy = (IPeople)Proxy.newProxyInstance(clazz.getClassLoader(),interfaces,hander);
        //结果打印
        System.out.println("-------------------------");
        tomProxy.goOut();
        System.out.println("-------------------------");
        tomProxy.goHome();
    }
}

通常代理创建的过程也可以封装成一个函数,可以自己完成。

结果打印:

-------------------------
before---检查手机钱包是否带齐...
Tom 要外出了...
-------------------------
Tom 回家了...
after---结算今日开销

小结:
代理模式的用途十分广泛,如Spring中的AOP等。另外代理模式与装饰模式十分相像,他们都能改变对象的行为,但装饰者模式更强调增加对象的职责与行为,即主要实现装饰者自由切换添加,而被装饰者不变;代理模式则强调添加每个行为的控制,增加固定的前置、后置处理等,即处理的对象不断变化,但处理方式不变

猜你喜欢

转载自blog.csdn.net/qq_38071004/article/details/79315916