Proxy模式又叫做代理模式,是构造型的设计模式之一,它可以为其他对象提供一种代理(Proxy)以控制对这个对象的访问。

  所谓代理,是指具有与代理元(被代理的对象)具有相同的接口的类,客户端必须通过代理与被代理的目标类交互,而代理一般在交互的过程中(交互前后),进行某些特别的处理。

  代理模式的结构

  代理模式的角色与职责

   1、subject(抽象主题角色):真实主题与代理主题的共同接口或抽象类。

   2、RealSubject(真实主题角色):定义了代理角色所代表的真实对象。

   3、Proxy(代理主题角色):含有对真实主题角色的引用,代理角色通常在将客户端调用传递给真是主题对象之前或者之后执行某些操作,而不是单纯返回真实的对象。

  举个例子说明一下代理模式

  比如说买书,网上有很多专门卖书的网站,我们从这些商城买书,但是书不是这些商城印的,他们只负责卖,书是出版社印的,所以说到底,我们其实还是从出版社买书,网上书城只是出版社的代理,所以出版社是被代理对象,书城是代理对象。

  所以,根据角色与职责划分,subject(抽象主题角色)就是卖书,卖书是书城与出版社的共同功能,RealSubject(真实主题角色)就是出版社,它的功能就是卖书,但不直接卖给用户,而是被书城代理,通过代理来卖,Proxy(代理主题角色)就是书城,根据概念发现,代理对象在代理的过程中不仅仅只有被代理对象的功能,他还会执行某些他自己的操作,这个意思是,比如,书城会推出优惠券与打折活动。在卖书的基础上,增加许多功能来吸引消费者。

  接下来,我们用代码实现刚才的例子:

  代理模式分为两种类型:(1)静态代理(2)动态代理

  (1)静态代理

  (静态代理在使用时,需要定义接口或者父类,被代理对象与代理对象一起实现相同的接口或者是继承相同父类)

  首先,创建subject,一个接口,是代理对象与被代理对象的共同接口

  书城与出版社都有卖书的功能

 public interface Subject {
public void sailBook();
}

  然后,创建RealSubject,被代理对象,也就是出版社

 public class RealSubject implements Subject {

     @Override
public void sailBook() {
System.out.println("卖书");
} }

  然后,创建代理对象,也就是书城

 public class ProxySubject implements Subject{
//代理对象含有对真实主题角色的引用
private Subject subject; public ProxySubject(Subject subject){
this.subject = subject;
} @Override
public void sailBook() {
dazhe();
this.subject.sailBook();
give();
} //代理角色通常在将客户端调用传递给真是主题对象之前或者之后执行某些操作,而不是单纯返回真实的对象。
public void dazhe(){
System.out.println("打折");
} public void give(){
System.out.println("赠送代金券");
} }

  最后,创建客户端,也就是用户

  首先如果,不使用代理直接从出版社买

 public class MainClass {
public static void main(String[] args) {
Subject realSubject = new RealSubject();
realSubject.sailBook();
}
}

  结果如下:仅仅是卖书

  而如果我们通过代理也就是书城来买

 public class MainClass {
public static void main(String[] args) {
Subject realSubject = new RealSubject();
Subject proxySubject = new ProxySubject(realSubject);
proxySubject.sailBook();
}
}

  结果变成了这样,作为用户,我们享受了更多的优惠,所以我们当然更愿意通过代理来买

  

  静态代理总结:
  1、可以做到在不修改目标对象的功能前提下,对目标功能扩展.
  2、缺点:因为代理对象需要与目标对象实现一样的接口,所以会有很多代理类,类太多.同时,一旦接口增加方法,目标对象与代理对象都要维护.

  如何解决静态代理中的缺点呢?答案是可以使用动态代理方式

  (2)动态代理

  动态代理有以下特点:

  1.代理对象,不需要实现接口

  2.代理对象的生成,是利用JDK的API,动态的在内存中构建代理对象(需要我们指定创建代理对象/目标对象实现的接口的类型)

  3.动态代理也叫做:JDK代理,接口代理

  代理代理,Subject与RealSubject不变

    而使用动态代理,首先要创建代理实例的调用处理程序,通过这个程序来执行代理对象特有的方法

  创建MyHandler实现InvocationHandler(是代理实例的调用处理程序 实现的接口)这个接口,并覆盖invoke(Object proxy, Method method, Object[] args)这个方法。

 Object invoke(Object proxy, Method method, Object[] args)
          在代理实例上处理方法调用并返回结果。
 1 import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method; public class MyHandler implements InvocationHandler{
//这里也需要传入被代理对象
private Subject subject; public MyHandler(Subject subject){
this.subject = subject;
} //这个方法中就是代理对象要执行的方法
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
dazhe();
//执行被代理对象中的方法
Object result = method.invoke(subject, args);
give();
return result;
} public void dazhe() {
System.out.println("打折");
} public void give() {
System.out.println("赠送代金券");
}
}

  最后,写客户端,客户端中需要动态创建代理对象,要使用Proxy类中的newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h)方法

static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h)
          返回一个指定接口的代理类实例,该接口可以将方法调用指派到指定的调用处理程序。

  参数:

  loader - 定义代理类的类加载器
  interfaces - 代理类要实现的接口列表
  h - 指派方法调用的调用处理程序
  返回:
  一个带有代理类的指定调用处理程序的代理实例,它由指定的类加载器定义,并实现指定的接口
  抛出:
  IllegalArgumentException - 如果违反传递到 getProxyClass 的参数上的任何限制
  NullPointerException - 如果 interfaces 数组参数或其任何元素为 null,或如果调用处理程序 hnull

  所以三个参数,第一个是RealSubject的类加载器,第二个是被代理类要实现的接口列表,第三个就是处理程序也就是MyHandler

 public class MainClass {
public static void main(String[] args) {
Subject realSubject = new RealSubject();
MyHandler myHandler = new MyHandler(realSubject);
//创建代理对象实例
Subject proxySubject = (Subject) Proxy.newProxyInstance(Subject.class.getClassLoader(), realSubject.getClass().getInterfaces(), myHandler);
proxySubject.sailBook();
}
}

  结果是相同的

   总结:代理对象不需要实现接口,但是目标对象一定要实现接口,否则不能用动态代理

java设计模式-----11、代理模式的更多相关文章

  1. Java设计模式之代理模式(静态代理和JDK、CGLib动态代理)以及应用场景

    我做了个例子 ,需要可以下载源码:代理模式 1.前言: Spring 的AOP 面向切面编程,是通过动态代理实现的, 由两部分组成:(a) 如果有接口的话 通过 JDK 接口级别的代理 (b) 如果没 ...

  2. java设计模式6——代理模式

    java设计模式6--代理模式 1.代理模式介绍: 1.1.为什么要学习代理模式?因为这就是Spring Aop的底层!(SpringAop 和 SpringMvc) 1.2.代理模式的分类: 静态代 ...

  3. 夜话JAVA设计模式之代理模式(Proxy)

    代理模式定义:为另一个对象提供一个替身或者占位符以控制对这个对象的访问.---<Head First 设计模式> 代理模式换句话说就是给某一个对象创建一个代理对象,由这个代理对象控制对原对 ...

  4. Java设计模式:代理模式(转)

    代理(Proxy)是一种设计模式,提供了对目标对象另外的访问方式;即通过代理对象访问目标对象.这样做的好处是:可以在目标对象实现的基础上,增强额外的功能操作,即扩展目标对象的功能.这里使用到编程中的一 ...

  5. Java 设计模式_代理模式(2016-08-19)

    概念: 代理模式是对象的结构模式.代理模式给某一个对象提供一个代理对象,并由代理对象控制对原对象的引用. 就是一个人或者机构代表另一个人或者机构采取行动.在一些情况下,一个客户不想或者不能够直接引用一 ...

  6. JAVA设计模式:代理模式&& 装饰模式区别

    在前面学习了代理模式和装饰模式后,发现对两者之间有时候会混淆,因此对两者进行了区别和理解: 装饰模式你可以这样理解,就像糖一样,卖的时候商家大多要在外面包一层糖纸,其实原本还是糖. public in ...

  7. Java设计模式:代理模式(二)

    承接上文 三.计数代理 计数代理的应用场景是:当客户程序需要在调用服务提供者对象的方法之前或之后执行日志或者计数等额外功能时,就可以用到技术代理模式.计数代理模式并不是把额外操作的代码直接添加到原服务 ...

  8. java设计模式之代理模式 ,以及和java 回调机制的区别

    java 代理模式就是: 将自己要做的事交给别人去做(这个别人就是代理者,自己就是被代理者),为什么自己能做的要交给别人去做了?假如一个小学生小明,现在要写作业,但是又想玩游戏,他更想玩游戏,并且不想 ...

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

    前言: 最近在研究Retrofit开源框架的时候,其主要核心代码是通过注解标示参数,动态代理模式实现具体接口,反射机制进行参数解析,最终实现发送请求.其实之前在学习Xutils源码的时候,Xutils ...

  10. Head First 设计模式 --11 代理模式

    代理模式:为另一个对象提供一个替身或占位符以控制对这个对象的访问. 代码: interface Boss { public void meeting(); } class BossImp implem ...

随机推荐

  1. 《Discuz安装时候出现乱码 -- 问题解决方法》

    自我安装discuz时出现安装界面乱码的情况,跟链接所说一样,经过原作的分享,加上我自己的实验,明白了,什么时候修改/usr/local/php/etc/php.ini里面的default_chars ...

  2. 使用JS代码实现点击按钮下载文件

    有时候我们在网页上需要增加一个下载按钮,让用户能够点击后下载页面上的资料,那么怎样才能实现功能呢?这里有两种方法: 现在需要在页面上添加一个下载按钮,点击按钮下载文件. 题外话,这个下载图标是引用的 ...

  3. chrome浏览器下JavaScript实现clipboard时无法访问剪切板解决方案

    在用JavaScript实现某个简单的复制到剪切板功能的时候,会考虑一下浏览器兼容性,主要是重点在IE和FireFox,把这个两个浏览器搞定后,基本上其他浏览器也不用太操心了,Chrome也一样,没出 ...

  4. Windows下Nginx的启动、停止等基本命令

    在Windows下使用Nginx,我们需要掌握一些基本的操作命令,比如:启动.停止Nginx服务,重新载入Nginx等,下面我就进行一些简单的介绍. 1.启动: C:\server\nginx-1.0 ...

  5. Mysql(六):数据备份、pymysql模块

    一 IDE工具介绍 生产环境还是推荐使用mysql命令行,但为了方便我们测试,可以使用IDE工具 下载链接:https://pan.baidu.com/s/1bpo5mqj 掌握: #1. 测试+链接 ...

  6. hdu1061(2015-N1):1.快速幂;2.找规律

    1.快速幂 原理:求a的b次方,将b转化为二进制数,该二进制位第i位的权是2^(i-1), 例如 11的二进制是1011 11 = 2³×1 + 2²×0 + 2¹×1 + 2º×1 因此,我们将a¹ ...

  7. OpenStack中memcached的使用和实现

    概述 主要分享下个人对Liberty版本openstack中cache使用的理解,由于作者水平有限,难免有所错误,疏漏,还望批评指正. openstack中可以使用cache层来缓存数据,Libert ...

  8. iOS.Animations.by.Tutorials.v2.0汉化(四)

    第三章 转换 在前面的两章,你学习了如何创建基于视图位置和透明度alpha的动画属性的动画.但是,如果您希望在视图上添加动画或删除动画,您将如何处理呢? 您可以使用前几章的方法来设置进出界面的动画效果 ...

  9. 【转载】Ubuntu环境下安装QT(转)

    Ubuntu 安装 Qt 开发环境 简单实现是本文要介绍的内容,内容很短,取其精华,详细介绍Qt 类库的说明,先来看内容. 一.Ubuntu下安装Qt $ sudo apt-get install q ...

  10. 【linux】php安装 出现Sorry, I cannot run apxs. ***错误解决方法

    首先, 通过错误提示, 我们得知"I cannot run apxs". 我一直以为是apxs安装有问题, 但找了很久仍未得到合理的解释和解决方法. 于是我直接运行"/u ...