代理模式

  代理模式即给一个真实类提供一个代理类,该代理类代替真实类完成其功能,一般还可在代理类上添加一些真实类不具有的附加功能,通俗来讲代理模式就是我们生活中常见的中介,代理模式又可分为静态代理动态代理

静态代理

  静态代理需要代理类和目标类实现一样的接口,一般将被代理对象组合到代理类中,然后使用其完成对应功能,并可在代理类中添加额外功能。

租房静态代理过程

第一步:创建服务接口

public interface Rent {
// 出租房屋
void rent();
}

第二步:实现类实现服务接口

public class Host implements Rent{
@Override
public void rent() {
System.out.println("房东要出租房子...");
}
}

第三步:代理类实现服务接口

public class Proxy implements Rent{
// 被代理的类,用于完成被代理类功能。
private Host host;
// 用于初始化被代理类
public void setHost(Host host) {
this.host = host;
}
// 完成被代理类的功能,同时可附加其他功能。
@Override
public void rent() {
doSomething();
host.rent();
doSomething();
}
// 附加的功能
private void doSomething() {
System.out.println("doSomething...");
}
}

第四步:编写测试类

public class Test {
public static void main(String[] args) {
Host host = new Host();
Proxy proxy = new Proxy();
proxy.setHost(host);
proxy.rent();
}
}

静态代理总结

优点

  • 高扩展性:可以在不修改目标类的前提下扩展目标类的功能。

缺点

  • 冗余:一个目标类就会产生一个代理类,会产生过多的代理类。
  • 开发效率低:代理类代码量繁重。
  • 不易维护:一旦接口改变,目标类与代理类都要进行修改。

动态代理

  动态代理中我们不需要手动的创建代理类,只需要编写一个动态处理器来为我们动态创建代理对象,代理对象由 JDK 在运行时动态创建,动态代理基于反射来实现

常用的动态代理方式

  • 基于接口的动态代理:由 JDK 提供,使用 JDK 官方的 Proxy 类创建代理对象。
  • 基于类的动态代理:由第三方 CGLib 提供,使用 CGLib 的 Enhancer 类创建代理对象
  • javassist
  • ……

基于接口的动态代理

  使用基于接口的动态代理首先需要了解 JDK 中的 Proxy 类和 InvocationHandler接口,然后用其编写动态处理器用于完成动态代理。

Proxy 类

  Proxy 提供了创建动态代理类和实例的静态方法,它也是由这些方法创建的所有动态代理类的超类。

  一般使用 Proxy 的 newProxyInstance 静态方法创建代理类,需要提供一个类加载器、被代理类的服务接口,以及一个 InvocationHandler 的对象。

  • 类加载器:用于加载类和接口
  • 被代理类的接口:提供被代理类服务接口信息
  • InvocationHandler 对象:用于执行被代理类的方法
public static Object newProxyInstance(ClassLoader loader,
Class<?>[] interfaces,
InvocationHandler h);

InvocationHandler 接口

  当在代理实例上调用方法时,方法调用被编码并分派到其调用处理程序的调用方法,即在 Proxy 中调用方法时,该方法调用被分派给 InvocationHandler 对象中的 invoke 方法执行,由 invoke 方法调用执行被代理对象的方法。

Object invoke(Object proxy, Method method, Object[] args);

动态处理器工具类

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy; public class ProxyInvocationHandler implements InvocationHandler {
// 被代理的接口
private Object target; public ProxyInvocationHandler() {
} public ProxyInvocationHandler(Object target) {
this.target = target;
} // 用于初始化被代理类
public void setTarget(Object target) {
this.target = target;
} // 生成得到代理类
public Object getProxy() {
return Proxy.newProxyInstance(this.getClass().getClassLoader(), target.getClass().getInterfaces(), this);
} // 处理代理示例并返回结果
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
return method.invoke(target, args);
}
}

基于接口的租房动态代理过程

第一步:创建服务接口

public interface Rent {
// 出租房屋
void rent();
}

第二步:实现类实现服务接口

public class Host implements Rent{
@Override
public void rent() {
System.out.println("房东要出租房子...");
}
}

第三步:编写动态处理器

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy; public class ProxyInvocationHandler implements InvocationHandler {
// 被代理的接口
private Object target; // 用于初始化被代理类
public void setTarget(Object target) {
this.target = target;
} // 生成得到代理类
public Object getProxy() {
return Proxy.newProxyInstance(this.getClass().getClassLoader(), target.getClass().getInterfaces(), this);
} // 处理代理示例并返回结果
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
doSomething();
Object invoke = method.invoke(target, args);
doSomething();
return invoke;
} // 附加的功能
private void doSomething() {
System.out.println("doSomething...");
}
}

第四步:编写测试类

public class Test {
public static void main(String[] args) {
Host host = new Host();
ProxyInvocationHandler proxyInvocationHandler = new ProxyInvocationHandler();
proxyInvocationHandler.setTarget(host);
Rent proxy = (Rent)proxyInvocationHandler.getProxy();
proxy.rent();
}
}

动态代理总结

优点

  • 高扩展性:可以在不修改目标类的前提下扩展目标类的功能。
  • 低冗余:会产生过多的代理类。
  • 低耦合:减少了对业务接口的依赖。
  • 高效开发:大大减少开发任务,一个动态处理器即可完成代理。

注意事项

  • 由于在客户端和真实主题之间增加了代理对象,因此有些类型的代理模式可能会造成请求的处理速度变慢。
  • 实现代理模式需要额外的工作,有些代理模式的实现非常复杂。
  • 和适配器模式的区别:适配器模式主要改变所考虑对象的接口,而代理模式不能改变所代理类的接口。
  • 和装饰器模式的区别:装饰器模式为了增强功能,而代理模式是为了加以控制。

你管这叫代理模式(Proxy Pattern)的更多相关文章

  1. 代理模式(Proxy pattern)

    代理模式(proxy pattern):作用:为其他对象提供一种代理,以控制对这个对象的访问.代理对象在客户端对象和目标对象之间起中介的作用. 代理模式涉及到的角色: 抽象角色:声明真实对象和代理对象 ...

  2. 乐在其中设计模式(C#) - 代理模式(Proxy Pattern)

    原文:乐在其中设计模式(C#) - 代理模式(Proxy Pattern) [索引页][源码下载] 乐在其中设计模式(C#) - 代理模式(Proxy Pattern) 作者:webabcd 介绍 为 ...

  3. 二十四种设计模式:代理模式(Proxy Pattern)

    代理模式(Proxy Pattern) 介绍为其他对象提供一个代理以控制对这个对象的访问. 示例有一个Message实体类,某对象对它的操作有Insert()和Get()方法,用一个代理来控制对这个对 ...

  4. 设计模式 - 代理模式(proxy pattern) 未使用代理模式 具体解释

    代理模式(proxy pattern) 未使用代理模式 详细解释 本文地址: http://blog.csdn.net/caroline_wendy 部分代码參考: http://blog.csdn. ...

  5. 设计模式系列之代理模式(Proxy Pattern)——对象的间接访问

    说明:设计模式系列文章是读刘伟所著<设计模式的艺术之道(软件开发人员内功修炼之道)>一书的阅读笔记.个人感觉这本书讲的不错,有兴趣推荐读一读.详细内容也可以看看此书作者的博客https:/ ...

  6. 13.代理模式(Proxy Pattern)

    using System; namespace Test { //抽象角色:声明真实对象和代理对象的共同接口. //代理角色:代理对象角色内部含有对真实对象的引用,从而可以操作真实对象, //同时代理 ...

  7. 设计模式——代理模式(Proxy Pattern)

    代理模式(Proxy),为其他对象提供一种代理以控制对这个对象的访问. UML图: 模型设计: Subject类: package com.cnblog.clarck; /** * Subject 类 ...

  8. 七个结构模式之代理模式(Proxy Pattern)

    定义: 给某一个对象提供一个代理或者占位符,并由代理类来控制对原对象的访问.代理对象在客户端和实际对象之间启到了中介作用,并且强调了代理类对原对象的控制作用.例如:安全代理.缓冲代理.远程代理等. 结 ...

  9. C#设计模式——代理模式(Proxy Pattern)

    一.概述在软件开发中,有些对象由于创建成本高.访问时需要与其它进程交互等原因,直接访问会造成系统速度慢.复杂度增大等问题.这时可以使用代理模式,给系统增加一层间接层,通过间接层访问对象,从而达到隐藏系 ...

  10. c#设计模式之代理模式(Proxy Pattern)

    引言 代理这个词语,大家在现实世界已经频繁的接触过,例如火车站代理售票点,因为这些代理售票点的存在,我们不必要去火车站的售票处就可以查询或者取到火车票.代理点本身是没有能力生产车票的,我们在代理处享受 ...

随机推荐

  1. CF24B F1 Champions 题解

    Content 有 \(n\) 场已经进行完的赛车比赛,每场比赛给出前 \(m\) 名的名字.在每场比赛中,前 \(10\) 名的选手分别可以获得 \(25,18,15,12,10,8,6,4,2,1 ...

  2. Tornado 之 WebSocket

    7.3 WebSocket WebSocket是HTML5规范中新提出的客户端-服务器通讯协议,协议本身使用新的ws://URL格式. WebSocket 是独立的.创建在 TCP 上的协议,和 HT ...

  3. mysql如何查询某个库,某个表都有哪些字段

    如下语句便可查看 SELECT column_name FROM Information_schema.columns  WHERE table_Name = 'columns' AND TABLE_ ...

  4. SpringBoot整合zimg图片服务器

    依赖 <dependency> <groupId>com.alibaba</groupId> <artifactId>fastjson</arti ...

  5. c++基础之虚函数表指针和虚函数表创建时机

    虚函数表指针 虚函数表指针随对象走,它发生在对象运行期,当对象创建的时候,虚函数表表指针位于该对象所在内存的最前面. 使用虚函数时,虚函数表指针指向虚函数表中的函数地址即可实现多态. 虚函数表 虚函数 ...

  6. 再谈多线程模型之生产者消费者(总结)(c++11实现)

    0.关于 为缩短篇幅,本系列记录如下: 再谈多线程模型之生产者消费者(基础概念)(c++11实现) 再谈多线程模型之生产者消费者(单一生产者和单一消费者)(c++11实现) 再谈多线程模型之生产者消费 ...

  7. windows修改控制台编码

    1.关于 演示环境: win10 1909 2.代码定义 编码代码 释义 65001 UTF-8代码页 950 繁体中文 936 简体中文默认的GBK 437 MS-DOS 美国英语 3.注册表修改 ...

  8. 【LeetCode】263. Ugly Number 解题报告(Java & Python)

    作者: 负雪明烛 id: fuxuemingzhu 个人博客: http://fuxuemingzhu.cn/ 目录 题目描述 题目大意 解题方法 除去2,3,5因子 日期 [LeetCode] 题目 ...

  9. 【LeetCode】448. Find All Numbers Disappeared in an Array 解题报告(Python)

    作者: 负雪明烛 id: fuxuemingzhu 个人博客: http://fuxuemingzhu.cn/ 目录 题目描述 题目大意 方法一:暴力求解 方法二:原地变负做标记 方法三:使用set ...

  10. 【LeetCode】845. Longest Mountain in Array 解题报告(Python)

    作者: 负雪明烛 id: fuxuemingzhu 个人博客: http://fuxuemingzhu.cn/ 目录 题目描述 题目大意 解题方法 双数组 参考资料 日期 题目地址:https://l ...