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. curl模拟请求

    GET请求 <?php //初始化 $curl = curl_init(); //设置抓取的url curl_setopt($curl, CURLOPT_URL, 'http://www.bai ...

  2. PHP中的浮点精度和类型

    PHP中的浮点数 精度 在PHP中,浮点数的字长和平台相关,通常最大值是 1.8e308 并具有 14 位十进制数字的精度(64 位 IEEE 格式). 浮点数的精度有限.尽管取决于系统,PHP 通常 ...

  3. vuejs、eggjs全栈式开发设备管理系统

    vuejs.eggjs全栈式开发简单设备管理系统 业余时间用eggjs.vuejs开发了一个设备管理系统,通过mqtt协议上传设备数据至web端实时展现,包含设备参数分析.发送设备报警等模块.收获还是 ...

  4. MysqL_SELECT FOR UPDATE详解

    先来举一个在某些应用场景下会出现数据不一致的例子,当然存储引擎是InnoDB(至于为什么,后面再告诉你). 电商平台常见的下单场景: 一般商品表(goods)有基本的四个字段,id(主键),goods ...

  5. pep 8 规范的一些记录

    一.pep8起源 龟叔创立Python的初衷里就有创立一个容易阅读的编程语言,所以亲自操刀写了pep8 代码规范,每个项目开始前都要有一个共识,就是自己的代码规范,pep8 就是一个很好的范本. 二. ...

  6. MS SQL xp_instance_regwrite设置注册表疑惑

      以前写过一篇博文"MS SQL 日志记录管理",里面介绍了如何设置SQL Server的错误日志的最大归档数量,如果在SSMS的UI界面设置,可以从"Manageme ...

  7. linux内核体系结构

    linux内核第一记   1.linux体系结构   从上图可知,Linux分为:用户空间和内核空间.内核空间和用户空间是程序执行的两种不同的状态,通过系统调用和硬件中断能够完成从用户空间到内核空间的 ...

  8. HeapAlloc,GlobalAlloc,LocalAlloc,VirtualAlloc,malloc,new的异同

    1. 首先我们来看HeapAlloc: MSDN上的解释为:HeapALloc是从堆上分配一块内存,且分配的内存是不可移动的(即如果没有连续的空间能满足分配的大小,程序不能将其他零散的 空间利用起来, ...

  9. Vxworks 6.6系列下载地址

    Vxworks 6.6系列下载地址: ---------------------------------- ftp://ftp.windriver.speedera.net/ftp.windriver ...

  10. 利用Eclipse中的Maven构建Web项目报错(一)

    利用Eclipse中的Maven构建Web项目 1.在进行上述操作时,pom.xml一直报错 <project xmlns="http://maven.apache.org/POM/4 ...