今天要开始我们结构型 设计模式的学习,设计模式源于生活,还是希望能通过生活中的一些小栗子去理解学习它,而不是为了学习而学习这些东西。

结构型设计模式

结构型设计模式又分为

  • 类 结构型
  • 对象 结构型

前者使用对象的继承机制来组织对象和类

后者采用组合聚合 的方式来组合对象。

代理模式 Proxy

理解代理一词 代理表达的是:为某个对象提供一种代理,用于控制该对象的访问,让客户端间接的访问该对象,从而限制、或者增强源对象的一些特性。

举个栗子

从国内科学SW,访问谷歌查阅一些资料的时候,我们肯定务必会借助一些代理器 也就是通常所说的VPN,代理的服务器可以帮助我们完成这些操作。

静态代理

画个图理解一下

需要说明的地方有:

  • 抽象父类或者接口:定义了这个代理可以代理的方法。比如定义了一个SearchSubject 实现它的子类必须要实现对应的search() 方法。
/**
* 抽象主题,可以进行搜索
*/
public abstract class SearchSubject {
/**
* 可以进行搜索的操作
*/
public abstract void search();
}
  • 真实对象:真实对象也就是具体将要被代理的方法,这个真实对象的方法我们要通过代理类间接的去访问。

众所周知,国内访问不到Google,需要代理才行。

public class Google extends SearchSubject {
@Override
public void search() {
System.out.println("Google 搜索引擎");
}
}
  • 代理类:也就是VPN ,帮助我们访问真实对象 的某些方法,并且还可以做一些增强。比如在访问真实对象之前做一些事情,之后做一些事情。
/**
* VPN 代理
* 静态代理也需要实现抽象主题
*/
public class VPNProxy extends SearchSubject {
/**
* 含有真实主题
*/
private Google google; @Override
public void search() {
if (null == google) {
google = new Google();
}
this.before();
/**
* 调用真实对象的方法
*/
google.search();
this.after();
}
/**
* 增强方法
*/
public void before() {
System.out.println("VPN 开始执行。。。");
}
public void after() {
System.out.println("VPN 结束执行");
}
}

执行调用代理

VPNProxy proxy = new VPNProxy();
proxy.search();
------------------
VPN 开始执行。。。
Google 搜索引擎
VPN 结束执行

以上就是我们要学习的第一种代理方式:静态代理

动态代理

假设我们还需要代理一个对象呢?比如必应 假设必应搜索我们国内访问不到,必须使用代理的话,是不是又得重新创建两个对象

  • 真实对象必应搜索
  • 代理对象必应搜索的代理

这就不利于我们系统的扩展性,假设有很多需要代理的,那岂不是写一大堆。

因此,动态代理由此而生。

这里我们使用JDK 提供的动态代理

public static Object newProxyInstance(ClassLoader loader,Class<?>[] interfaces,InvocationHandler h){}
  • ClassLoader 类加载器
  • interfaces 加载的接口
  • InvocationHandler 增强处理器以及调用代理的类

创建一个可供实现的搜索接口

/**
* 搜索接口
*/
public interface SearchInterface {
String search();
}

谷歌搜索引擎实现了这个接口,并且将名称作为返回值返回。

public class GoogleSearch implements SearchInterface {
@Override
public String search() {
System.out.println("Google 搜索引擎");
return "Google";
}
}

创建一个搜索增强器,并且创建了两个方法的增强,在调用代理之前和之后,都加入了一些方法。

/**
* 搜索处理器
*/
public class SearchHandler implements InvocationHandler { private void before() {
System.out.println("handler start");
} private void after() {
System.out.println("handler stop");
} private SearchInterface obj; public SearchHandler(SearchInterface obj) {
this.obj = obj;
} @Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { this.before();
/**
* 执行代理方法
*/
Object result = method.invoke(obj, args);
System.out.println("result=" + result.toString());
this.after(); return result;
}
}

创建一个动态代理工厂,将我们需要代理的接口传入,并且传入接口的处理类,即可实现接口的增强处理。

/**
* 动态代理工厂
*/
public class ProxyFactory {
/**
* 目标对象
*/
private SearchInterface object;
private InvocationHandler handler; public ProxyFactory(SearchInterface obj, InvocationHandler handler) {
this.object = obj;
this.handler = handler;
}
/**
* 获取代理对象
* @return
*/
public Object getProxyObj() {
ClassLoader classLoader = object.getClass().getClassLoader();
Class<?>[] interfaces = object.getClass().getInterfaces();
return Proxy.newProxyInstance(classLoader, interfaces, handler);
}
}

创建一个具体的接口对象,传入我们的代理工厂,并且将其处理器也同时传入,我们就可以得到一个代理对象。

        SearchInterface search = new GoogleSearch();

        System.out.println("1id=" + search);
InvocationHandler handler = new SearchHandler(search); ProxyFactory factory = new ProxyFactory(search, handler);
SearchInterface google = (SearchInterface) factory.getProxyObj(); System.out.println("2id=" + google);
google.search();
-----------------
1id=impl.GoogleSearch@1b6d3586 handler start
result=impl.GoogleSearch@1b6d3586
handler stop 2id=impl.GoogleSearch@1b6d3586
handler start
Google 搜索引擎
result=Google
handler stop

从上面的代码我们发现:

  • 代理的对象与我们创建的对象有所不同
  • 在生成代理对象的时候、已经执行了一遍invoke() 方法
  • 通过代理对象调用具体方法的时候也执行了一遍invoke()

老衲画个图

这样就好理解多了,代理工厂需要一个代理类、以及这个代理类的增强方法(处理器),通过代理工厂生成的代理对象,实现对对象的增强处理。

动态代理的总结

  • 代理类不需要实现接口,但是具体对象还是需要实现接口。

Cglib代理

上面两种代理,都是需要代理类、或者是具体的目标对象实现某个接口的基础上出现的,假设没有这个接口的显示,我只想在某个具体的对象上加入增强的话,如何实现呢?

Cglib代理又被称作子类代理,就是代理一个具体的子类

因为Spring 已经引入了相关的Cglib 的依赖,我们直接在Spring 的环境下进行测试。

创建一个具体的子类。没有实现任何的接口

public class BingSearch {
public void search() {
System.out.println("必应搜索。。。");
}
}

创建类实现一个方法拦截器,其实名字就是这样叫的。我们的代理对象,是通过工具类拿出来的。

public class ProxyFactory implements MethodInterceptor {

    //维护目标对象
private Object target; public ProxyFactory(Object target) {
this.target = target;
}
private void before() {
System.out.println("代理类前置处理。。");
}
private void after() {
System.out.println("代理类后置处理。。");
}
public Object getProxy() {
//1.工具类
Enhancer en = new Enhancer();
//2.设置父类
en.setSuperclass(target.getClass());
//3.设置回调函数
en.setCallback(this);
//4.创建子类(代理对象)
return en.create();
}
@Override
public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable { /**
* 执行方法
*/
this.before();
Object result = method.invoke(target, objects);
this.after();
return result;
}
}

在main 方法对一个具体的类进行增强代理。

    public static void main(String[] args) {

        ProxyFactory proxyFactory = new ProxyFactory(new BingSearch());

        BingSearch bing = (BingSearch) proxyFactory.getProxy();
bing.search();
}
---------
代理类前置处理。。
必应搜索。。。
代理类后置处理。。

小结

本节,将我们最常用的两种代理模式进行了一些讲解,其实最重要的是JDK动态代理 和Cglib 具体方法代理增强。因为大家已经拥抱Spring 的怀抱了,这两种代理还是很重要的,Spring的AOP 切面也是一种基于动态代理的方式实现。非常好用,在Spring 声明式事务当中,一个注解即可搞定许多冗余的编程式事务,这无不归功于 强大的动态代理

鸣谢&参考

https://www.cnblogs.com/leeego-123/p/10995975.html

代码

https://gitee.com/mrc1999/Dev-Examples

欢迎关注

JAVA设计模式 5【结构型】代理模式的理解与使用的更多相关文章

  1. Java设计模式(10)代理模式(Proxy模式)

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

  2. 结构型--代理模式(Proxy)

    一.代理模式是什么? 代理模式属于GOF23设计模式中结构型中的设计模式,通过代理对象来屏蔽(部分或者屏蔽)对真实对象的直接访问,下图为UML图: 在代理模式中组件包括:抽象角色接口.代理角色类.真实 ...

  3. JAVA设计模式(09):结构型-代理模式(Proxy)

    代理模式是经常使用的结构型设计模式之中的一个,当无法直接訪问某个对象或訪问某个对象存在困难时能够通过一个代理对象来间接訪问,为了保证client使用的透明性,所訪问的真实对象与代理对象须要实现同样的接 ...

  4. Java设计模式之结构型模式

    结构型模式,共七种:适配器模式.装饰器模式.代理模式.外观模式.桥接模式.组合模式.享元模式. 一.适配器模式: 意图: 将一个类的接口转换成客户希望的另外一个接口.Adapter 模式使得原本由于接 ...

  5. Java设计模式系列之动态代理模式(转载)

    代理设计模式 定义:为其他对象提供一种代理以控制对这个对象的访问. 动态代理使用 java动态代理机制以巧妙的方式实现了代理模式的设计理念. 代理模式示例代码 public interface Sub ...

  6. Java设计模式---(动态)代理模式

    代理设计模式 定义:为其他对象提供一种代理以控制对这个对象的访问. 动态代理使用 java动态代理机制以巧妙的方式实现了代理模式的设计理念. 之前虽然会用JDK的动态代理,但是有些问题却一直没有搞明白 ...

  7. JAVA设计模式——第 2 章 代理模式【Proxy Pattern】(转)

    什么是代理模式呢?我很忙,忙的没空理你,那你要找我呢就先找我的代理人吧,那代理人总要知道被代理人能做哪些事情不能做哪些事情吧,那就是两个人具备同一个接口,代理人虽然不能干活,但是被代理的人能干活呀. ...

  8. Java设计模式(八)----代理模式

    代理模式 1.生活中: 代理就是一个人或者一个组织代表其它人去做一件事的现实生活中的. 在一些情况下,一个客户不想或者不能够直接引用一个对象,而代理对象能够在client和目标对象之间起到中介的作用. ...

  9. java设计模式,工厂,代理模式等

    javaEE设计模式: 工厂模式:主要分为三种模式: 定义:在基类中定义创建对象的一个接口,让子类决定实例化哪个类.工厂方法让一个类的实例化延迟到子类中进行. 为什么要使用工厂模式: (1) 解耦 : ...

  10. java设计模式案例详解:代理模式

    代理模式就是用一个第三者的身份去完成工作,其实际意义跟字面意思其实是一样的,理解方式有很多,还是例子直观. 本例的实现类是实现买票功能,实际应用想要添加身份验证功能,利用代理模式添加验证步骤.上例子: ...

随机推荐

  1. 控制流程之while循环, for循环

    条件循环:while,语法如下 while 条件: # 循环体 # 如果条件为真,那么循环体则执行,执行完毕后再次循环,重新判断条件... # 如果条件为假,那么循环体不执行,循环终止死循环 基本使用 ...

  2. kubernetes系列(十四) - 存储之PersistentVolume

    1. PersistentVolume(PV)简介 1.1 为什么需要Persistent Volume(PV) 1.2 PersistentVolume(PV)和Volume的区别 1.3 PV和P ...

  3. 读《大话设计模式》——应用策略模式的"商场收银系统"(WinForm)

    策略模式的结构 这个模式涉及到三个角色: 环境(Context)角色:持有一个 Strategy 类的引用.抽象策略(Strategy)角色:这是一个抽象角色,通常由一个接口或抽象类实现.此角色给出所 ...

  4. scrapy(一):基础用法

    Scrapy 框架 Scrapy 简介 Scray 是用python写的为了爬取网站数据,提取结构性数据的应用框架 Scrapy框架原理图 白话讲解Scrapy 运作流程 代码写好,程序开始运行... ...

  5. cnn卷积理解

    首先输入图像是28*28处理好的图. 第一层卷积:用5*5的卷积核进行卷积,输入为1通道,输出为32通道.即第一层的输入为:28*28图,第一层有32个不同的滤波器,对同一张图进行卷积,然后输出为32 ...

  6. 03-Python控制语句

    一.简介 通过一些语句来改变程序的执行顺序,这些语句被叫做控制语句,在python主要有if.for.while三种控制流语句. 二.if语句 用来检测一个条件是否成立,如果为真,则执行该语句(一般为 ...

  7. 用python批量处理Excel表格,处理结果又快又好,做办公室最靓的那个仔

    使用python批量处理Excel数据     让你根据Excel上所有人的身份证号码,提取出公司员工的生日 让你每个月都将公司所有人的考勤数据整理一下 类似这样的格式化的重复操作,你还在每次都使用的 ...

  8. P1866 编号

    大致题意: 求太郎的n只兔子的编号的排列种数 基本思路: 每只兔子都有一个范围,那么每只兔子的范围就是这只兔子选择编号的种数. 以5 8为例,第一只兔子有5种,第二只兔子有8种,而第一只兔子选择后,第 ...

  9. IDEA 编译 Jmeter 5.0

    IDEA 编译 Jmeter 5.0 1.下载源码后解压,我这边下载的是最新的『apache-jmeter-5.0_src.tar』,解压. 2.解压后 修改下列两个文件 eclipse.classp ...

  10. Newbe.Claptrap 框架入门,第二步 —— 简单业务,清空购物车

    接上一篇 Newbe.Claptrap 框架入门,第一步 —— 创建项目,实现简易购物车 ,我们继续要了解一下如何使用 Newbe.Claptrap 框架开发业务.通过本篇阅读,您便可以开始尝试使用 ...