浅谈设计模式之代理模式(proxy)

Posted ZzQ的鱼

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了浅谈设计模式之代理模式(proxy)相关的知识,希望对你有一定的参考价值。

一、定义

        为这个对象提供一种代理以达到控制对这个对象的访问。在某些情况下,一个对象不适合或者不能直接引用另一个对象[业务场景],而代理对象可以在客户端和目标对象之间起到中介的作用。

二、特征

     代理类与委托类有同样的接口。(用JAVA的语言来说就是有实现同样的接口)

    代理模式结构图(图片来自《大话设计模式》)

三、静态代理&动态代理

    1)、静态代理

     指在译阶段就已经明确创建指定了接口、代理对象的被代理对象,主要是代理对象的明确建立,固定【静态代理】被代理对象。

    2)动态代理

    指在运行阶段动态创建代理对象,代理对象运行期间动态变化。


相比于静态代理, 动态代理的优势在于可以很方便的对代理类的函数进行统一的处理,而不用修改每个代理类中的方法。


四、通俗案例

静态代理:

    经纪人有一个唱歌的行为(接口),摇滚歌手A会唱摇滚的歌,歌迷有想听歌摇滚的歌直接找歌手来唱,这样看起来经纪人好像没什么用;有一天经纪人跟摇滚歌手签合同,摇滚歌手要唱歌只能通过经纪人同意才行,那么歌迷想听摇滚歌手唱歌的时候只能通过经纪人渠道来听歌了,而经纪人要收门票费用,那么这个过程就是静态代理,收取费用就是代理的作用(功能)了;静态就是经纪人只有摇滚歌手A,没办法改其他人了


动态代理:

    在静态的基础之上,流行歌手B会唱流行歌曲歌迷,那么同一个经纪人就要跟流行歌手继续签合同,歌迷想听流行歌手还是一样要找经纪人,经纪人一样还是要收门票费用,但是这个似乎还经纪人就变成一个动态代理经纪人了,歌迷想听什么歌都可以了。


经纪人=代理类

歌手=被代理类

收取额外费用=功能

总结:静态代理(1:1)可以简单理解成动态代理(1:N)的进一步抽象


五、代码范例

静态代理:

/**
* 歌手接口
*/
public interface SingerInterface {

//唱歌方法
void singing();
}


/**
* 摇滚歌手
*/
public class RockSingerService implements SingerInterface{

public void singing(){
System.out.println("我是摇滚歌手,开始唱歌");
}
}



/**
* 经纪人
*/
public class SingerProxyService implements SingerInterface{

private RockSingerService rockSingerService;
public void
singing(){
System.out.println("摇滚歌手已经跟我签约了,我是代理,我要收门票");
rockSingerService.singing();
System.out.println("摇滚歌手已经唱完歌了,我赚钱了我要送福利给歌迷,哈哈哈");
}

public RockSingerService getRockSingerService() {
return rockSingerService;
}

public void setRockSingerService(RockSingerService rockSingerService) {
this.rockSingerService = rockSingerService;
}
}



/**
* 点唱
*/
public class Main {

public static void main(String[] args) {

//创建一个摇滚歌手
RockSingerService rockSingerService = new RockSingerService();
//创建一个经纪人
SingerProxyService singerProxyService = new SingerProxyService();
//签约
singerProxyService.setRockSingerService(rockSingerService);
//粉丝向经纪人要求摇滚歌手唱歌
singerProxyService.singing();
}
}


输出:

摇滚歌手已经跟我签约了,我是代理,我要收门票

我是摇滚歌手,开始唱歌

摇滚歌手已经唱完歌了,我赚钱了我要送福利给歌迷,哈哈哈


动态代理:

实现动态代理有多种方式,我就在上面的基础上用java的java.lang.reflect包下提供了一个Proxy类和一个InvocationHandler接口,通过这个类和这个接口可以生成JDK动态代理类和动态代理对象

/**
* 经典歌手
*/
public class ClassesSingerService implements SingerInterface{

public void singing(){
System.out.println("我是经典歌手,开始唱歌");
}
}


public class DynamicMain {

public static void main(String[] args) {

//创建摇滚歌手
//点名要经典歌手唱歌
RockSingerService rockSingerService = new RockSingerService();
//创建动态代理模板类
DynamicProxyService dynamicProxyService = new DynamicProxyService();
dynamicProxyService.setProxyObject(rockSingerService);
//通过反射生成具体摇滚歌手代理类->Proxy
SingerInterface rockSinger = (SingerInterface)Proxy.newProxyInstance(
dynamicProxyService.getClass().getClassLoader(),
rockSingerService.getClass().getInterfaces()
,dynamicProxyService);
//唱歌
rockSinger.singing();
System.out.println("=====================================================");
//点名要经典歌手唱歌
ClassesSingerService classesSingerService = new ClassesSingerService();
dynamicProxyService.setProxyObject(classesSingerService);
SingerInterface classesSinger = (SingerInterface)Proxy.newProxyInstance(
dynamicProxyService.getClass().getClassLoader(),
classesSingerService.getClass().getInterfaces()
,dynamicProxyService);
//唱歌
classesSinger.singing();
}
}



输出:

com.sun.proxy.$Proxy0已经跟我签约了,我是代理,我要收门票

我是摇滚歌手,开始唱歌

com.sun.proxy.$Proxy0已经唱完歌了,我赚钱了我要送福利给歌迷,哈哈哈

=====================================================

com.sun.proxy.$Proxy0已经跟我签约了,我是代理,我要收门票

我是经典歌手,开始唱歌

com.sun.proxy.$Proxy0已经唱完歌了,我赚钱了我要送福利给歌迷,哈哈哈



以上是个人学习总结,如说的不对,欢迎给以指出,谢谢!




以上是关于浅谈设计模式之代理模式(proxy)的主要内容,如果未能解决你的问题,请参考以下文章

浅谈源码的七大设计模式

设计模式之代理模式(Proxy)详解及代码示例

设计模式之代理模式 Proxy

设计模式之- 代理模式(Proxy Pattern)

Java设计模式之代理模式(Proxy)

JAVA SCRIPT设计模式--结构型--设计模式之Proxy代理模式(12)