代理模式(为了Rxjava,Retrofit....)

以下都是本人收集和总结的内容:

1.什么是代理模式

代理模式(Proxy Pattern)也称作为委托模式。在生活中代理也是随处可见,例如香港代购,代理品牌电脑出售店等。而在开发中也是被经常被使用到的一种设计模式。代理模式的作用是:为其他对象提供一种代理以控制对这个对象的访问。对于代理模式可以分为两大类,分别是静态代理和动态代理。下面就开始对这两种类型的代理模式进行详细介绍。

2. 什么是静态代理

在这里通过一个场景来展开描述代理模式。现在我想按照自己想要的配置来组装一台电脑。于是我将主板,内存条,显卡,机箱,显示器等所有的配件都买回来了。可是这个时候遇到了一个难题,我不会组装呀。于是我带着这些配件去找专业人士为我组装电脑。对于电脑的组装内部细节部分步骤比较多。在这里作为举例说明,将组装电脑的过程主要分为三个步骤。这三个步骤分别是安装主机,设置显示器,安装操作系统。

2.1 静态代理简单实现

接下来我们针对上述场景,来实现代理模式。首先来看一下它的UML类图。

代理uml

从上述大概看出代理模式创建很简单。在这里定义了一个电脑公司的接口。在这个接口里面是一些出售电脑并且组装的实现步骤。而后又定义了一个客户类和一个销售的代理类,分别实现这个接口。之后出售电脑的这些事情全部都交由这个销售代理类来实现。下面就来看一下具体的代码实现。
  这里定义一个电脑公司的接口,在接口里面分别定义了对电脑的出售,主机的安装和操作系统的安装。

public interface IComputerFirmbuild {
    void saleComputer();
    void installHost();
    void installOS();
}

下面这个是客户类,实现了IComputerFirmbuild接口。也是对电脑服务的具体操作步骤。

public class Customer implements IComputerFirmbuild{

    @Override
    public void saleComputer() {
        System.out.println("购买电脑");
    }

    @Override
    public void installHost() {
        System.out.println("安装主机");
    }

    @Override
    public void installOS() {
        System.out.println("安装操作系统");
    }

}

还有个代理类。这个代理类同样也继承自IComputerFirmbuild接口。在这个代理类中还持有被代理的引用,也就是Customer类。通过调用被代理类Customer的方法,来实现代理功能。

public class SalerProxy implements IComputerFirmbuild{

    private IComputerFirmbuild saler;

    public SalerProxy(IComputerFirmbuild saler) {
        this.saler = saler;
    }
     
    @Override
    public void saleComputer() {
        this.Saler.saleComputer();
    }
    
    @Override
    public void installHost() {
        this.Saler.installHost();
    }

    @Override
    public void installOS() {
        this.saler.installOS();
    }

}

下面就通过一个Client类,来看一下具体的调用执行关系。

public class Client {

    public static void main(String[] args) {
        IComputerFirmbuild customer = new Customer();
        IComputerFirmbuild proxy = new SalerProxy(customer);
        proxy.saleComputer();
        proxy.setDisplay();
        proxy.installOS();
    }

}

在这个Client类中,可以看到,所有的事情都交由代理类处理了。然后在看一下运行结果。

log -->  购买电脑
log -->  安装主机
log -->  安装操作系统

对于这个代理类中,也能够实现不同的接口来完成不同功能的整合。在这里就不在详细赘述。下面就来看一下代理模式的通用代码。

2.2静态代理通用模板

在这里首先来看一下代理模式的通用类图。

代理模式的通用类图.jpeg

ISubject(抽象主题类):在这个类中,主要声明真实主题类和代理类的共同方法。它既可以是一个接口也可以是一个抽象类。
  RealSubject(真实主题类):这是被代理类,具体的业务实现都在这个类中。
  Proxy(代理类):这是一个代理类,在这个代理类中它持有真实主题类的对象。通过调用真实主题类的方法来实现代理。
  下面来看一下通用代码:
  抽象主题类

public interface ISubject {
   public void request();
}

实现抽象主题的真实主题类

public class RealSubject implements ISubject{

    @Override
    public void request() {
        System.out.println("我是真实对象");
    }
}

代理类

public class Proxy implements ISubject{

    private ISubject subject;

    public Proxy(ISubject subject) {
        this.subject = subject;
    }

    @Override
    public void request() {
        this.subject.request();
    }

}

客户类

public class Client {
    public static void main(String[] args) {
        ISubject subject = new RealSubject();
        Proxy proxy = new Proxy(subject);
        proxy.request();
    }
}

以上就是静态代理类的实现。
  从上面的分析出可以看出,对静态代理模式,代理者的代码都是通过程序员或者是通过一些自动化的工具生成的固定代码然后再对他们进行编译。这样也就意味着在我们的代码运行之前代理类的Class文件就已经存在了。

3. 什么是动态代理

3.1动态代理简单实现

在这里再来看一下动态代理。对于动态代理,在程序运行时,动态的创建一个代理类以及代理类的对象,当然也能够创建一个实现多个接口的代理类。在动态代理类中使用了Java中的反射机制,来生成了代理类的对象。并且Java也为我们提供了一个动态代理接口InvocationHandler,对被代理类的方法进行代理。在使用动态代理类时,必须实现InvocationHandler接口。
  对于InvocationHandler接口,我们必须手动实现的它的invoke方法,正是在InvocationHandler中的invoke方法中完成了对真实方法的调用。也就是说所有被代理的方法都是交由这个InvocationHandler进行处理。在这里首先看一下这个InvocationHandler接口。

动态代理.png

下面就来看一下具体的代码实现。对于上面的IComputerFirmbuild接口和Customer不需要改变。所以在这里只需要一个实现InvocationHandler接口的CustomerHandler类。然后在对Client做一次修改即可。在这里看一下CustomerHandler类。

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

public class CustomerHandler implements InvocationHandler{

    private Object obj = null;

    public CustomerHandler(Object object) {
        this.obj = object;
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        // TODO Auto-generated method stub
        return method.invoke(this.obj, args);
    }

}

再看一下Client类。

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

public class Client {
    public static void main(String[] args) {
        IComputerFirmbuild computerFirmbuild = new Customer();
        InvocationHandler handler = new CustomerHandler(computerFirmbuild);
        IComputerFirmbuild proxy = (IComputerFirmbuild)Proxy.newProxyInstance(computerFirmbuild.getClass().getClassLoader(), 
                new Class[]{IComputerFirmbuild.class}, handler);
        proxy.saleComputer();
        proxy.installHost();
        proxy.installOS();
    }

}

这样就通过动态代理模式实现了上述的情形。对于运行结果与上面一样,在这里就不在贴出。下面来看一下动态代理的通用模板。

通过DynamicProxy,RealSubject可以在运行时动态改变,需要控制的接口Subject也可以在运行时改变,控制的方式DynamicSubject类也可以动态改变,从而实现了非常灵活的动态代理关系。

3.2动态代理通用模板

在这里再看一下动态代理的通用类图。

动态代理的通用类图.jpeg

在这里通过DynamicProxy来创建一个Proxy对象。并且它依赖于InvocationHandler。并且是InvocationHandler来进行实际的业务处理。下面就来看一下动态代理的通用代码。   
抽象主题类

public interface ISubject {
    void request();
}

真实主题类

public class RealSubject implements ISubject{
  @Override
    public void request() {
        //业务处理
    }

}

InvocationHandler的实现类

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

public class MyInvocationHandler implements InvocationHandler{
   private Object target = null;
 public MyInvocationHandler(Object object) {
        this.target = object;
    }
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {

        return method.invoke(this.target, args);
    }

}

DynamicProxy类

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

public class DynamicProxy<T> {
   @SuppressWarnings("unchecked")
    public static <T> T newProxyInstance(ClassLoader classLoader, Class<?>[] interfaces,InvocationHandler handler){
        return (T)Proxy.newProxyInstance(classLoader, interfaces, handler);
    }
}

Client类

public class Client {
    public static void main(String[] args) {
        ISubject subject = new RealSubject();

        InvocationHandler handler = new MyInvocationHandler(subject);
        ISubject proxy = DynamicProxy.newProxyInstance(subject.getClass().getClassLoader(), subject.getClass().getInterfaces(), handler);
        proxy.request();
    }
}

4. 总结

从代理模式可以看出代理对象可以在客户端和目标对象之间起到中介的作用,这样起到了中介的作用和保护了目标对象的作用,并且扩展性很高。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,732评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 87,496评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,264评论 0 338
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,807评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,806评论 5 368
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,675评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,029评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,683评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 41,704评论 1 299
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,666评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,773评论 1 332
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,413评论 4 321
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,016评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,978评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,204评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,083评论 2 350
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,503评论 2 343

推荐阅读更多精彩内容

  • 整体Retrofit内容如下: 1、Retrofit解析1之前哨站——理解RESTful 2、Retrofit解析...
    隔壁老李头阅读 3,220评论 2 10
  • Spring Cloud为开发人员提供了快速构建分布式系统中一些常见模式的工具(例如配置管理,服务发现,断路器,智...
    卡卡罗2017阅读 134,596评论 18 139
  • 我一直都很喜欢理财博主--三公子,微信订阅号也是每篇必读。我虽然工作时间没有多久,但我之前是月光族,还欠信用卡的那...
    DL诺尔阅读 656评论 0 1
  • 中秋节刚过,家里的桌子上还堆了两盒月饼,看着也真是发愁,一盒是小区物业发的福利,简简单单的包装;另外一盒是朋...
    Yumi玉米粒阅读 348评论 1 2
  • 是人就会有低潮期吧,不管是感情的还是事业的,亦或是身体健康的低潮期,这也很符合客观规律,人生是条曲线而不是直线,...
    tong言言阅读 510评论 2 1