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. Linux一些常用操作

    1.linux swap分区 可采用文件的方式 dd if=/dev/zero of=/var/swap bs=1024 count=2048000 mkswap /var/swap swapon / ...

  2. js中的typeof和instanceof和===

    typeof: 用于判断number/string/boolean/underfined类型/function 不能判断:null和object ,不能区分object和Array instanceo ...

  3. mac 上格式化磁盘出现MediaKit报告设备上的空间不足以执行请求的解决办法

    1.问题描述: 我使用是一个2T移动硬盘,分了5个区 2.分析原因:因为mac OSX的日志式格式需要有EFI分区进行引导,而我的移动硬盘是没有EFI分区的,这样的话就会出现问题: 3.解决办法: 1 ...

  4. Docker 入门之创建service(一)

    在一个分布式应用中,我们把应用的不同层叫做"Services".比如,一个视频共享应用,它包含存储数据到数据库的服务,用户上载后后台进行的视频解码服务,前端服务等等. 然而,一个服 ...

  5. 原生javascript 的MAP使用

    var map = {}; // Map map = new HashMap();map[key] = value; // map.put(key, value);var value = map[ke ...

  6. 支付宝wap支付调起客户端

    https://mclient.alipay.com/home/exterfaceAssign.htm?alipay_exterface_invoke_assign_client_ip=183.15. ...

  7. Jmeter MD5插件

    实际业务中,会要求 HTTP 协议中附加 MD5 校验字段, 防止请求参数被恶意篡改, 对于开发同学来说, 这是个很简单的需求. 但是给自动化测试增加了难度, Jmeter 原生不支持这个功能,应测试 ...

  8. Java线程编程中isAlive()和join()的使用详解

    一个线程如何知道另一线程已经结束?Thread类提供了回答此问题的方法. 有两种方法可以判定一个线程是否结束.第一,可以在线程中调用isAlive().这种方法由Thread定义,它的通常形式如下: ...

  9. 让UltraEdit成为java编译器

      1. ?        配置命令: 选择[高级]->[工具栏配置] ?        选择插入按钮进行命令添加: ?        依次填写命令内容: 解释:菜单项目名称:命令的名字,建议使 ...

  10. java程序调用xfire发布的webService服务(二)

    在上一篇的调用xfire发布的webService服务中,我只是从服务端返回了一个字符串给客户端,却没有测试从客户端传递数据给服务端.而实际应用中一般是不太可能只出现这样的应用场景的,因此我便更进一步 ...