Proxy??

Proxy是“代理人”的意思,它指的是代替别人进行工作的人。代理实际上就是使用委托的机制,在代理的过程中你可以做点其他的事情,然后再来执行被代理对象的代码。

  • 知识储备

1.什么时候使用:

GoF书(请参见附录E[GoF])在讲解Proxy模式时,使用了一个可以在文本中嵌入图形对象(例如图片等)的文本编辑器作为例子。为了生成这些图形对象,需要读取图片文件,这很耗费时间。因此如果在打开文档时就生成有所的图形对象,就会导致文档打开时间过长。所以,最好是当用户浏览至文本中各个图形对象时,再去生成它们的实例。这时,Proxy模式就有了用武之地。

2.有那些代理:

  • Virtual Proxy(虚拟代理)Virtual Proxy就是本章中学习的Proxy模式。只有当真正需要实例时,它才生成和初始化实例。

  • Remote Proxy(远程代理)Remote Proxy可以让我们完全不必在意RealSubject角色是否在远程网络上,可以如同它在自己身边一样(透明性地)调用它的 方法。Java的RMI(RemoteMethodInvocation:远程方法调用)就相当于Remote Proxy。

  • Access Proxy Access Proxy 用于在调用RealSubject角色的功能时设置访问限制。例如,这种代理可以只允许指定的用户调用方法,而当其他用户调用方法时则报错。

  • 静态代理

    1.使用委托机制代理人只代理他能解决的问题。当遇到他不能解决的问题时,还是会“转交”给本人去解决。

    这里的“转交”就是在本书中多次提到过的“委托”。从PrinterProxy类的print方法中调用real.print方法正是这种“委托”的体现。

  1. 为了实现PrinterProxy类可以从printer类中分离出来作为独立的组件使用,而且只要是实现了Printable接口的类都可以扮演Proxy的角色。需要使用反射实例

private synchronized void realize(String classname) {
if(real==null){
try {
real = ((Printable) Class.forName(classname).newInstance());
}catch (ClassNotFoundException e){
System.out.println("没有发现"+classname);
}catch (Exception e){
e.printStackTrace();
}
}
}
  • 动态代理

在java的动态代理机制中,有两个重要的类或接口,一个是 InvocationHandler(Interface)、另一个则是 Proxy(Class),这一个类和接口是实现我们动态代理所必须用到的。首先我们先来看看java的API帮助文档是怎么样对这两个类进行描述的:

InvocationHandler:


InvocationHandler is the interface implemented by the invocation handler of a proxy instance. Each proxy instance has an associated invocation handler. When a method is invoked on a proxy instance,
the method invocation is encoded and dispatched to the invoke method of its invocation handler.

每一个动态代理类都必须要实现InvocationHandler这个接口,并且每个代理类的实例都关联到了一个handler,当我们通过代理对象调用一个方法的时候,这个方法的调用就会被转发为由InvocationHandler这个接口的 invoke 方法来进行调用。我们来看看

InvocationHandler这个接口的唯一一个方法 invoke 方法:

Object invoke(Object proxy, Method method, Object[] args) throws Throwable

我们看到这个方法一共接受三个参数,那么这三个参数分别代表什么呢?


Object invoke(Object proxy, Method method, Object[] args) throws Throwable proxy:  指代我们所代理的那个真实对象
method:  指代的是我们所要调用真实对象的某个方法的Method对象
args:  指代的是调用真实对象某个方法时接受的参数

理清职责

  • 实现一个带名字的打印机

    名字=====》》说明

    Printer || 表示带名字的打印机的类(本人)

    Printable || Printer和PrinterProxy的共同接口

    PrinterProxy || 表示带名字的打印机的类(代理人)

    Main ||测试程序行为的类

UML

类图:

时序图:

Code

  • Printable


public interface Printable {

    // 设置打印名字
void setPrinterName(String name); // 获取打印名字
String getPrinterName(); // 显示文字
void print(String string);
}
  • Printer


public class Printer implements Printable{

    private String name;

    public Printer() {
heavyjob("正在生成Printer实例");
} public Printer(String name) {
this.name = name;
heavyjob("正在生成Printer实例("+name+")");
} /**
* 模拟一个高负载任务
* @param string
*/
private void heavyjob(String string) {
System.out.println(string);
for (int i = 0; i < 5; i++) {
try {
Thread.sleep(1000);
}catch (InterruptedException e){
e.printStackTrace();
}
System.out.print(".");
}
} @Override
public void setPrinterName(String name) {
this.name=name;
} @Override
public String getPrinterName() {
return name;
} @Override
public void print(String string) {
System.out.println("==="+name+"===");
System.out.println(string);
}
}
  • PrinterProxy


public class PrinterProxy implements Printable{

    private String name;

    private Printer real;

    /**
* 不论 setPrinterName 方法和getPrinterName 方法被调用多少次,
* 都不会生成Printer类的实例。只有当真正需要本人时,
* 才会生成printer类的实例(printerProxy类的调用者完全不知道是否生成了本人,也不用在意是否生成了本人)。
* @param name
*/ public PrinterProxy(String name) {
this.name = name;
} @Override
public synchronized void setPrinterName(String name) {
if(real!=null){
real.setPrinterName(name);
}
this.name=name;
} @Override
public String getPrinterName() {
return name;
} @Override
public void print(String string) {
realize();
real.print(string);
} private synchronized void realize() {
if(real==null) real=new Printer(name);
}
} public class MainT {
public static void main(String[] args) { Printable p=new PrinterProxy("Tom");
System.out.println("现在是"+p.getPrinterName());
p.setPrinterName("Cat");
System.out.println("现在是"+p.getPrinterName());
p.print("我是 Tomcat"); }
}
  • 结果:


现在是Tom
现在是Cat
正在生成Printer实例(Cat)
.....
===Cat===
我是 Tomcat

动态代理Code



public class Client {

    public static void main(String[] args) {

        Printable tom = new Printer("Tom");

        DynamicProxy proxy = new DynamicProxy(tom);

        Printable o = (Printable) Proxy.newProxyInstance(proxy.getClass().getClassLoader(),
tom.getClass().getInterfaces(), proxy); System.out.println(o.getClass().getName()); System.out.println("现在是"+o.getPrinterName());
o.print("Tomcat");
}
} public class DynamicProxy implements InvocationHandler { private Object object; public DynamicProxy(Object object) {
this.object = object;
} @Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { System.out.println("准备执行"); System.out.println("Method:" + method); Object o = method.invoke(object, args); System.out.println("执行完毕");
return o;
}
} public interface Printable { // 设置打印名字
void setPrinterName(String name); // 获取打印名字
String getPrinterName(); // 显示文字
void print(String string);
} public class Printer implements Printable{
private String name; public Printer() {
heavyjob("正在生成Printer实例");
} public Printer(String name) {
this.name = name;
heavyjob("正在生成Printer实例("+name+")");
} /**
* 模拟一个高负载任务
* @param string
*/
private void heavyjob(String string) {
System.out.println(string);
for (int i = 0; i < 5; i++) {
try {
Thread.sleep(1000);
}catch (InterruptedException e){
e.printStackTrace();
}
System.out.print(".");
}
} @Override
public void setPrinterName(String name) {
this.name=name;
} @Override
public String getPrinterName() {
return name;
} @Override
public void print(String string) {
System.out.println("==="+name+"===");
System.out.println(string);
}
}
  • 关于代理Proxy 中proxy参数使用

1.proxy参数运行时的类型是什么

proxy的类型是:com.sun.proxy.$Proxy0真实的代理对象

2.为什么不用this替代

因为this代表的是InvocationHandler接口实现类本身,并不是真实的代理对象。

整体代码:



interface I_Db_Tools{
void open();
void close();
I_Db_Tools exchangeDb(String dbname);
}
class Db_Tools implements I_Db_Tools{
public void open() {
System.out.println("数据库连接..........");
}
public void close() {
System.out.println("数据库关闭..........");
}
@Override
public I_Db_Tools exchangeDb(String db_name) {
System.out.println("改变数据为:"+db_name);
return this;
}
}
public class ProxyD {
public static void main(String[] args) { I_Db_Tools db_Tools = new Db_Tools(); I_Db_Tools db_tools_proxy = ((I_Db_Tools) Proxy.newProxyInstance(db_Tools.getClass().getClassLoader(),
db_Tools.getClass().getInterfaces(), new InvocationHandler() {
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
// 利用proxy实现代理返回同一个对象
if ("exchangeDb".equals(method.getName())) {
String db_name=(String) args[0];
System.out.println("改变数据为:"+db_name);
return proxy;
}
if ("open".equals(method.getName())) {
return method.invoke(db_Tools, args);// 代理open方法
}
return null;//不代理其他方法
}
}));
I_Db_Tools db = db_Tools.exchangeDb("mysql").exchangeDb("Oracle");
db_tools_proxy.open();
db_tools_proxy.close();
}
}

Proxy模式(代理[延迟]模式)的更多相关文章

  1. 设计模式(十三): Proxy代理模式 -- 结构型模式

      设计模式(十一)代理模式Proxy(结构型) 1.概述 因为某个对象消耗太多资源,而且你的代码并不是每个逻辑路径都需要此对象, 你曾有过延迟创建对象的想法吗 ( if和else就是不同的两条逻辑路 ...

  2. 深度剖析Istio共享代理新模式Ambient Mesh

    摘要:今年9月份,Istio社区宣布Ambient Mesh开源,由此引发国内外众多开发者的热烈讨论. 本文分享自华为云社区<深度剖析!Istio共享代理新模式Ambient Mesh>, ...

  3. 设计模式GOF23(结构型模式:代理模式,适配模式,桥接模式,组合模式,装饰模式,外观模式,享元模式)

    结构型模式: – 分类: • 适配器模式.代理模式.桥接模式.装饰模式.组合模式.外观模式.享元模式 – 核心作用:是从程序的结构上实现松耦合,从而可以扩大整体的类结构,用来解决更大的问题.   结构 ...

  4. 简介Python设计模式中的代理模式与模板方法模式编程

    简介Python设计模式中的代理模式与模板方法模式编程 这篇文章主要介绍了Python设计模式中的代理模式与模板方法模式编程,文中举了两个简单的代码片段来说明,需要的朋友可以参考下 代理模式 Prox ...

  5. MyBatis之代理开发模式

    1 mybatis-Dao的代理开发模式 Dao:数据访问对象 原来:定义dao接口,在定义dao的实现类 dao的代理开发模式 只需要定义dao接口,由mybatis产生dao接口的实现类. 1.1 ...

  6. axios 两种异步模式,代理模式 和 异步模式

    axios 两种异步模式,代理模式 和 异步模式

  7. 【C# .Net GC】延迟模式 latencyMode 通过API-GC调优

    延迟模式 lowlatency 使用环境:后台工作方式只影响第 2 代中的垃圾回收:第 0 代和第 1 代中的垃圾回收始终是非并发的,因为它们完成的速度很快.GC模式是针对进程配置的,进程运行期间不能 ...

  8. 设计模式之Proxy(代理)(转)

    理解并使用设计模式,能够培养我们良好的面向对象编程习惯,同时在实际应用中,可以如鱼得水,享受游刃有余的乐趣. Proxy是比较有用途的一种模式,而且变种较多,应用场合覆盖从小结构到整个系统的大结构,P ...

  9. Java设计模式(13)模板模式(Template模式)

    Template模式定义:定义一个操作中算法的骨架,将一些步骤的执行延迟到其子类中. 其实Java的抽象类本来就是Template模式,因此使用很普遍.而且很容易理解和使用,我们直接以示例开始: pu ...

随机推荐

  1. 2017-2018-1 20179203 《Linux内核原理与分析》第五周作业

    攥写人:李鹏举 学号:20179203 ( 原创作品转载请注明出处) ( 学习课程:<Linux内核分析>MOOC课程http://mooc.study.163.com/course/US ...

  2. Django中的事务(Transaction)管理

    Django默认的事务行为 默认情况下,在Django中事务是自动提交的.当我们运行Django内置的模板修改函数时,例如调用model.save()或model.delete()时,事务将被立即提交 ...

  3. C# 中常用LInq操作

    static void Main(string[] args) { , , , , , , }; , , , , , , }; , , , , , , , , , , , }; // 交集 var f ...

  4. HDOJ1022(模拟栈)

    Train Problem I Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others)T ...

  5. UML核心元素--边界

    定义:边界是无形的,是可大可小的,同时参与者.用例和边界又有着相生相克的性质.与其说边界是UML元素,还不如说它是一种分析方法. 1.需求是动态的过程:系统边界是无形的,看不到的,不好理解,倒不如说需 ...

  6. JavaScript中的BOM知识框架

    浏览器对象模型(BOM)以window对象为依托,表示浏览器窗口及可见区域.同时,window对象和还是全局对象,因此所有求安局变量和函数都是它的属性,所有原生框架及其他函数都在它命名之下.BOM中对 ...

  7. webStorage

    1.HTML5中的本地存储概念是什么? 很多时候我们会存储用户本地信息到电脑上,例如:比方说用户有一个填充了一半的长表格,然后突然网络连接断开了,这样用户希望你能存储这些信息到本地,当网络恢复的时候, ...

  8. IIS7.0(虚拟机)发布MVC5程序出现Http403错误的解决方法.

    近来,用MVC5开发自己的一个小网站.网上租用了一个小空间(虚拟主机),可选.net版本为2.0 3.0 3.5 4.0 ,上传网站 后发现是403错误.不能访问. 经与技术人员联系,把虚拟机更换到高 ...

  9. Select 标签的默认值设置

    以下是网上“借鉴”的:(http://blog.csdn.net/nairuohe/article/details/6307367/) 比如<select class="selecto ...

  10. CSDN优秀博客连接,博客之星连接。

    点击链接 获得[红杏出墙]插件,FQ上网无压力!谷歌搜索无压力! 2013年度CSDN十大博客之星 TOP 作者 专注领域 博客地址 邹晓艺 机器学习及算法 zouxy09 2 王然 潜在的集大成者 ...