设计模式之——代理设计模式

代理模式说白了就是中介,A要完成C,并不是直接去完成而是委托中介B去完成,B就是连接A与C的代理,B可以完全替代A去做,有时只需要提供满足C所需要的东西就行。

代理模式分为静态代理(手动实现这些行为的替换) + 动态代理(实现InvocationHandler接口交给虚拟机实现行为的替换)

静态代理

我是一个客户想买一辆车开开,我可以提供买车所有的证件以及买车的行为(具备这些我当然自己就可以去买车了,但是我闲的蛋疼啊,自己去做这些事,毕竟日理万机的工作)
首先呢,我提取了我和中介的共同行为:那就是都可以买车,只是他没有我的相关证件
package com.zndroid.dm.ProxyModel.StaticProxy;

/**
 * Created by luzhenyu on 2017/7/27.
 */

public interface IBuyCar {

    void buyCar();
}
package com.zndroid.dm.ProxyModel.StaticProxy;

/**
 * Created by luzhenyu on 2017/7/27.
 */

public class Client implements IBuyCar {

    private int money;
    private String certificate;
    private String car;

    public String getCar() {
        return car;
    }

    public void setCar(String car) {
        this.car = car;
    }

    public int getMoney() {
        return money;
    }

    public void setMoney(int money) {
        this.money = money;
    }

    public String getCertificate() {
        return certificate;
    }

    public void setCertificate(String certificate) {
        this.certificate = certificate;
    }

    @Override
    public void buyCar() {
        System.out.println("客户 - 签合同");
    }

}
去4儿子店,找到一个中介,他客气滴招待了我,建立了我和他的联系(通过这个联系他能够拿到我的相关信息),他本身也具备买车的行为
package com.zndroid.dm.ProxyModel.StaticProxy;

/**
 * Created by luzhenyu on 2017/7/27.
 * 相当于中介
 * 通常建议使用的是聚合式代理而非继承式代理
 * 聚合实现方式中代理类聚合了被代理类,且代理类及被代理类都实现了同一个接口,可实现灵活多变。继承式的实现方式则不够灵活;
 * 比如,在管理员操作的同时需要进行权限的处理,操作内容的日志记录,操作后数据的变化三个功能。三个功能的排列组合有6种,
 * 也就是说使用继承要编写6个继承了Admin的代理类,而使用聚合,仅需要针对权限的处理、日志记录和数据变化三个功能编写代理类,
 * 在业务逻辑中根据具体需求改变代码顺序即可。
 */

public class Proxy implements IBuyCar {

    private Client client;//包含客户的引用,这样中介就能给我要相关的证件资料了

    public Proxy(Client client) {
        this.client = client;
    }

    @Override
    public void buyCar() {
        checkMoney$Certificate();

        client.buyCar();//具体实体(客户)动作(也就是最终需要客户签合同操作,代理只起到中介作用,而且客户关心的只是买车,证件检查等操作客户无需关心,交给中介做)

        shangPai();

        client.setCar(jiaoFu());
    }

    private void checkMoney$Certificate() {
        System.out.println("代理 - 资料核实:" + client.getCertificate() + " and " + client.getMoney());//代理做的东西
    }

    private void shangPai() {
        System.out.println("代理 - 上牌");//代理做的东西
    }

    private String jiaoFu() {
        System.out.println("代理 - 交付车辆");//代理做的东西
        return "new car";
    }
}
具体使用:
Client mClient = new Client();
mClient.setMoney(100);
mClient.setCertificate("ID card");
Proxy proxy = new Proxy(mClient);
proxy.buyCar();
log("客户获得了:" + mClient.getCar());
log("----------------我是分割线-----------------");

动态代理

基本和静态代理一样,只是要实现InvocationHandler接口,并告诉虚拟机怎么去处理手动插入的过程
package com.zndroid.dm.ProxyModel.DynamicProxy;

/**
 * Created by luzhenyu on 2017/7/27.
 */

public interface IBuyCar {

    void buyCar();
}
package com.zndroid.dm.ProxyModel.DynamicProxy;

/**
 * Created by luzhenyu on 2017/7/27.
 */

public class Client implements IBuyCar {

    private int money;
    private String certificate;

    public int getMoney() {
        return money;
    }

    public void setMoney(int money) {
        this.money = money;
    }

    public String getCertificate() {
        return certificate;
    }

    public void setCertificate(String certificate) {
        this.certificate = certificate;
    }

    @Override
    public void buyCar() {
        System.out.println("客户 - 签合同");
    }
}
package com.zndroid.dm.ProxyModel.DynamicProxy;

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

import static java.lang.System.out;

/**
 * Created by luzhenyu on 2017/7/27.
 * 一般来说,对代理模式而言,一个主题类与一个代理类一一对应,这也是静态代理模式的特点。
 * 但是,也存在这样的情况,有n各主题类,但是代理类中的“前处理、后处理”都是一样的,仅调用主题不同。
 * 也就是说,多个主题类对应一个代理类,共享“前处理,后处理”功能,动态调用所需主题,大大减小了程序规模,这就是动态代理模式的特点.
 *
 * 动态代理是不需要手写代理类的,但是需要实现InvocationHandler接口,在运行时由虚拟机创建代理,
 * 实际内部原理 参见<a>http://blog.csdn.net/goskalrie/article/details/52458773<a/>
 */

public class MyInvocationHandler implements InvocationHandler {
    private Object target;

    public MyInvocationHandler(Object object) {
        this.target = object;
    }

    /**
     *@param proxy 被代理的对象
     *@param method 被代理对象的方法
     *@param args 方法的参数
     *@return Object 方法返回值
     */
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        if (method.getName().equals("buyCar")) {
            checkMoney$Certificate();
        }

        method.invoke(target, args);

        if (method.getName().equals("buyCar")) {
            shangPai();
        }
        return null;
    }

    private void checkMoney$Certificate() {
        String s = "", s1 = "";
        try {
            Method m = target.getClass().getMethod("getMoney", null);
            s = String.valueOf(m.invoke(target, null));
            Method m1 = target.getClass().getMethod("getCertificate", null);
            s1 = (String)m1.invoke(target, null);
        } catch (NoSuchMethodException e) {
            e.printStackTrace();
        } catch (InvocationTargetException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        }

        System.out.println("代理 - 资料核实:" + s + " " + s1);//代理做的东西
    }

    private void shangPai() {
        System.out.println("代理 - 上牌");//代理做的东西
    }

    public String jiaoFu() {
        System.out.println("代理 - 交付车辆");//代理做的东西
        return "new car";
    }

    public Object getProxy() {
        return Proxy.newProxyInstance(target.getClass().getClassLoader(), target.getClass().getInterfaces(), this);
    }
}
具体使用:
MyInvocationHandler invocationHandler = new MyInvocationHandler(client);
((IBuyCar) (invocationHandler.getProxy())).buyCar();
log("客户获得了:" + invocationHandler.jiaoFu());
log("----------------我是分割线-----------------");



【欢迎上码】

【微信公众号搜索 h2o2s2】


猜你喜欢

转载自blog.csdn.net/luzhenyuxfcy/article/details/77747245