Java/Android设计模式<三> 代理模式 - CSDN博客

251 阅读4分钟

代理模式在我看来是android中最常见,比较重要的一个设计模式;代理模式实际上就是设置了一个新的对象(中介),也可以理解为真实对象的替身;

1.代理模式的组成:

//抽象主题 真实主题和代理主题的共同继承的接口

public interface Subject {

    void operation();

}

//真实主题

public class RealSubject implements Subject {


    public RealSubject(......) {
        ......
    }

    @Override
    public void operation() {
        //the real operation
    }

}

//代理主题 就是真实主题的替身 实现抽象主题 在构造中参数为真实主题

public class ProxySubject implements Subject {

    public Subject subject;

    //展开代理主题的构造中传入真实主题
    public ProxySubject(Subject subject) {
        this.subject = subject;
    }

     @Override
    public void operation() {
        subject.operation();
    }

}

2.代理模式的优缺点

优点:
1.代理对象作为调用(cleint)者和真实对象的媒介,可以降低模块之间的耦合性
2.如果真是对象的实例化较麻烦,代理的出现可以提高系统运行的速率
3.真实对象在某些时候会禁止实例化,这时候代理对象就称为唯一可以调用真实对象的媒介(反射除外)
4.提高代码的扩展性

缺点: 由于调用者和真实主题之间添加了一层代理 所以有些时候吊用起来会有一部分的耗时;

3.代码实现 —-> 静态代理

静态代理, 顾名思义,就是在编译之前代码中就已经创建了真实主题,抽象主题,代理主题的相关class;
这里我们以天气预报为例,进行案例展示:
//抽象主题接口的实现:

public interface Iweather {


    /**
     * 获取时间
     * 获取地区
     * 获取天气详细内容
     * */

    void getTime();
    void getState();
    void getContent();
}

在抽象主题中自定义一部分通用的方法,供真是主题和代理主题的对系那个来实现;

//接着来看真是主题的实现:


public class Weather implements Iweather {
    public String time;
    public String state;
    public String content;

    public Weather(String time, String state, String content) {
        this.time = time;
        this.state = state;
        this.content = content;
    }

    @Override
    public void getTime() {
        LogUtils.show("当前时间" + time);
    }

    @Override
    public void getState() {
        LogUtils.show("当前时间" + state);
    }

    @Override
    public void getContent() {
        LogUtils.show("当前时间" + content);
    }
}

真是主题其实就是实现了抽象主题中定义的方法;

//下面来看代理主题:

public class ProxyWeather implements Iweather {

    public Weather weather;

    public ProxyWeather(Weather weather) {
        this.weather = weather;
    }

    @Override
    public void getTime() {
        LogUtils.show("打开电视---切换频道");
        weather.getTime();
    }

    @Override
    public void getState() {
        LogUtils.show("当前地区为北京");
        weather.getState();
    }

    @Override
    public void getContent() {

        weather.getContent();
        LogUtils.show("针对天气预报 做出相关穿衣措施");
    }
}

代理主题是关键 ,他和真事主题一样实现了抽象主题接口;在构造中将真是主题对象传入,然后在对应的抽象接口方法中调用 真是主题对象.方法, 这样他就完全取代了真实主题的功能;
其次代理主题中可以添加一些自定义的操作;
比如在调用真实主题相关方法之前或者之后进行一些操作,比如:

        LogUtils.show("打开电视---切换频道");
        weather.getTime();

这样代理主题相比于真实主题扩展性就增强,与client的耦合性大大降低;
当然 在有些时候 真是主题是不允许初始化的,必须完全由代理来代替;b
比如真实主题的初始化太耗费资源或者出于安全问题等等 ;这时候如果client访问到真是主题,我们可以这样些代码:


public class Weather implements Iweather {
    public String time;
    public String state;
    public String content;

    private Weather(String time, String state, String content) {
        this.time = time;
        this.state = state;
        this.content = content;
    }

    @Override
    public void getTime() {
        //LogUtils.show("打开电视---切换屏道");
        LogUtils.show("当前时间" + time);
    }

    @Override
    public void getState() {
        LogUtils.show("当前时间" + state);
    }

    @Override
    public void getContent() {
        LogUtils.show("当前时间" + content);
    }


    public ProxyWeather getInstance(){
        return new ProxyWeather(this);
    }
}

这样真实主题的构造被私有化 然后不能new对象 只能通过getInstance来获取代理对象;

最后看client调用代码 和结果展示

 Weather weather = new Weather("19:00", "北京", "多云转晴");
        ProxyWeather proxyWeather = new ProxyWeather(weather);
        LogUtils.show("下班回家,准备看天气预报");
        LogUtils.show("...");
        proxyWeather.getTime();
        LogUtils.show("...");
        proxyWeather.getState();
        LogUtils.show("...");
        proxyWeather.getContent();
        LogUtils.show("...");
        LogUtils.show("准备吃晚饭");

结果:
这里写图片描述

4.代码实现 —-> 动态代理

当然在代理中最常用的还是动态代理;使用静态代理,代理关系必须固定,一个真是类就必须创建相应的代理类,有时候会比较冗余;但是动态代理不同,动态代理是通过反射来决定代理什么对象,简单的来说就是一套代码,使用于所有不同类型的真实主题;

ok 下面来看代码 抽象主题和真实主题沿用静态代理的类; 直接看代理主题的代码:


public class ProxyHandler implements InvocationHandler{


    private Object tar;

//这里传入的参数就是真实主题的实例化对象
    public Object newInsance(Object tar){
        this.tar = tar;
        return Proxy.newProxyInstance(tar.getClass().getClassLoader(),
                tar.getClass().getInterfaces(),this);
    }


    @Override
    public Object invoke(Object o, Method method, Object[] objects) throws Throwable {
        //do something
        // if (method.getName().equals("getTime")){
        //    LogUtils.show("...播报时间....");
        // }
        Object invoke = method.invoke(tar, objects);
        return invoke;
    }
}

同样,最后看client调用代码 和结果展示

  Weather weather = new Weather("19:00", "北京", "多云转晴");
        ProxyHandler proxyHandler = new ProxyHandler();
        Iweather iweather 
        = (Iweather) proxyHandler.newInsance(weather);
        LogUtils.show("下班回家,准备看天气预报");
        LogUtils.show("...");
        iweather.getTime();
        LogUtils.show("...");
        iweather.getState();
        LogUtils.show("...");
        iweather.getContent();
        LogUtils.show("...");
        LogUtils.show("准备吃晚饭");

结果:
这里写图片描述

ok 当这里就结束了 感谢阅读~