代理模式在我看来是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 当这里就结束了 感谢阅读~