首页 > 其他分享 >08【代理设计模式】

08【代理设计模式】

时间:2022-12-21 11:35:06浏览次数:41  
标签:真实 对象 08 代理 设计模式 方法 public


文章目录

  • ​​八、代理设计模式​​
  • ​​8.1 结构型设计模式简介​​
  • ​​8.2 代理设计模式简介​​
  • ​​8.2.1 代理设计模式概述​​
  • ​​8.2.2 代理设计模式的UML类图​​
  • ​​8.3 代理设计模式的实现​​
  • ​​8.3.1 静态代理和动态代理简介​​
  • ​​8.3.2 静态代理的实现​​
  • ​​8.3.3 动态代理的实现​​
  • ​​1)JDK动态代理​​
  • ​​2)CGLIB代理​​
  • ​​8.3.4 JDK代理和GBLIB代理的区别​​
  • ​​8.4 代理设计模式优缺点​​


八、代理设计模式

8.1 结构型设计模式简介

结构型模式(Structural Pattern)关注类和对象的组合。其描述如何将类或者对象结合在一起形成更大的结构,就像搭积木,可以通过简单积木的组合形成复杂的、功能更为强大的结构。

结构型模式可以分为类结构型模式和对象结构型模式:

  • 1)类结构型模式:类结构型模式关心类的组合,由多个类可以组合成一个更大的系统,在类结构型模式中一般只存在继承和实现关系。
  • 2)对象结构型模式:对象结构型模式关心类与对象的组合,通过关联关系使得在一个类中定义另一个类的实例对象,然后通过该对象调用其方法。

由于组合关系或聚合关系比继承关系耦合度低,满足“合成复用原则”,所以对象结构型模式比类结构型模式具有更大的灵活性,因此大部分结构型模式都是对象结构型模式。

8.2 代理设计模式简介

8.2.1 代理设计模式概述

代理设计模式(Proxy Pattern):指为其他对象提供一种代理,以控制这个对象的访问;

由于某种原因,一个对象不能够直接引用另一个对象时,代理对象可起到一个中介作用。即用代理对象来调用目标对象(被代理对象,资源的真实拥有者),并且代理对象也可以在目标对象的实现基础上进行增强,另外代理对象可以控制目标对象的访问,进行安全控制

Tips:代理模式主要的功能就是对类进行增强,并且对目标对象进行安全控制;

生活中的代理有很多场景:

调用者(客户端)

代理角色

真实角色(目标对象)

买电脑的人

电脑代理商

生产电脑的厂商

买火车票

黄牛

火车站,12306

租房子

房子中介

房东

我们发现代理角色真实角色都具有相同的功能(卖电脑/卖票),代理商可以在中间赚取差价(修改原有的功能)。

8.2.2 代理设计模式的UML类图

代理设计模式中一般包含3个角色:

  • 1)抽象主题(Subject):用于规范真实角色和代理角色拥有共同的业务方法;
  • 2)真实主题(RealSubject):实现了抽象主题中的具体业务,提供业务的和兴功能;也叫目标对象
  • 3)代理主题(Proxy):实现了真实主题所实现的所有接口,确保与真实主题拥有同样的方法,即保证真实主题的所有方法都能代理到,器内部含有真实主题的引用,可以调用真实主题的核心方法;可以在调用真实主题的方法前后进行功能的增强,也可以进行真实主题的方法访问控制;

08【代理设计模式】_代理模式

8.3 代理设计模式的实现

8.3.1 静态代理和动态代理简介

代理模式分为静态代理动态代理

  • 静态代理:静态代理类在编译期就生成,在不修改源代码的情况下,静态代理类是不会发生改变的,当真实对象扩展了一个方法时,必须要手动的修改静态代理类来确保能够代理到真实对象最新的方法;
  • 动态代理:动态代理类是在Java运行时动态生成的,当真实对象扩展任意方法时,动态代理类也会自动的扩展方法,不需要我们修改源代码;在Java中,动态代理分为JDK动态代理和CGLIB动态代理;

【案例】设计一套租房程序:

如果我们要去租房,需要去找房东,但是房东很可能不在家,但是房东会把房子交给中介,我们可以去中介寻找合适的房源;这就是一个典型的代理模式,目标对象是房东,房子是在房东手里的,中介是代理对象,对目标对象进行增强(我们在中介手里租的房子肯定比房东收的价格要贵);

8.3.2 静态代理的实现

  • 抽象主题:
package com.pattern.demo01;

/**
* @author lscl
* @version 1.0
* @intro: 抽象主题
*/
public interface IHouse {
// 海景房
void seaViewRoom();

// 江景房
void riverViewRoom();
}
  • 真实主题(房东,资源的真实拥有者):
package com.pattern.demo01;

/**
* @author lscl
* @version 1.0
* @intro: 房东,房子的实际拥有者(真实对象也叫目标对象)
*/
public class HouseOwner implements IHouse{
@Override
public void seaViewRoom() {
System.out.println("海景房...");
}

@Override
public void riverViewRoom() {
System.out.println("江景房...");
}
}
  • 代理主题(中介):
package com.pattern.demo01;

/**
* @author lscl
* @version 1.0
* @intro: 房子的代理商(中介)
*/
public class HouseProxy implements IHouse {

// 拥有房东的引用(资源不在代理对象这里,而是通过真实对象获取到真实资源)
private HouseOwner houseOwner;

public HouseProxy(HouseOwner houseOwner) {
this.houseOwner = houseOwner;
}

@Override
public void seaViewRoom() {

System.out.println("多收1000元");

// 调用真实资源
houseOwner.seaViewRoom();

System.out.println("豪华级服务...");
}

@Override
public void riverViewRoom() {

System.out.println("多收500元");
houseOwner.riverViewRoom();
System.out.println("贵宾级服务...");
}
}
  • 测试代码:
package com.pattern.demo01;

/**
* @author lscl
* @version 1.0
* @intro:
*/
public class Demo01_静态代理 {
public static void main(String[] args) {
// 创建一个代理对象
IHouse house=new HouseProxy(new HouseOwner());

house.riverViewRoom();
System.out.println("-------------------");
house.seaViewRoom();
}
}

运行效果:

08【代理设计模式】_设计模式_02

8.3.3 动态代理的实现

在静态代理中,房东如果新增了新的房源,如果中介要代理心得房源则必须修改源代码,这样一来程序的耦合性高,为了降低耦合,我们提供了动态代理的概念;

动态代理:即代理类在Java运行时生成,并不需要我们自己编写,当我们对目标对象新增或减少方法时,代理对象会自动的增加或减少;Java中实现动态代理有两种方式,分别是JDK提供的动态代理以及Spring框架提供的CGLIB代理;

1)JDK动态代理

JDK动态代理主要是Proxy类来完成的。

  • Proxy类:

public static Object newProxyInstance(ClassLoader loader, Class[] interfaces, InvocationHandler h) 作用:生成一个代理对象

loader

和目标对象一类的类加载器

interfaces

目标对象所有实现的接口的字节码对象

h

是一个接口,传一个匿名内部类做为实现类,并且重写其中的方法来实现代理的功能

返回值

返回代理对象

  • InvocationHandler接口

Object invoke(Object proxy, Method method, Object[] args) 作用:这个接口中的方法会调用多次,每个方法都会调用一次,用来实现代理方法的功能

proxy

代表生成的代理对象,不建议在方法中直接调用,不然会出现递归调用。

method

目标对象的方法对象

args

调用方法时传递的参数数组

返回值

返回当前这个方法调用的返回值

  • 示例代码:
package com.pattern.demo01;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;

/**
* @author lscl
* @version 1.0
* @intro:
*/
public class Demo02_动态代理 {
public static void main(String[] args) {

// 与目标对象一类的类加载器
ClassLoader appClassLoader = HouseOwner.class.getClassLoader();

// 目标对象实现的所有接口的字节码对象
Class<?>[] targetInterfaces = HouseOwner.class.getInterfaces();

// 调度对象,当代理对象执行方法时,会执行调度对象中的invoke方法
InvocationHandler handler = new InvocationHandler() {
/**
*
* @param proxy: 代理对象
* @param method:
* @param args
* @return
* @throws Throwable
*/
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {

String methodName = method.getName();

System.out.println("执行的方法是: " + methodName);

// 执行目标方法(必须传递目标对象来执行),返回目标方法的返回值
Object returnVal = method.invoke(new HouseOwner(), args);

return returnVal;
}
};

IHouse proxy = (IHouse) Proxy.newProxyInstance(
appClassLoader,
targetInterfaces,
handler
);

proxy.riverViewRoom();
}
}

执行效果:

08【代理设计模式】_uml_03

Tips:JDK的动态代理是基于接口的代理,JDK正是根据传递目标对象实现接口的字节码对象来生成代理类的;

2)CGLIB代理

CGLIB代理是Spring框架提供的API,在spring-core依赖中已经集成,并且GBLIB代理不依赖于接口。CGLIB代理是在运行期间生成一个子类继承目标对象来达到代理的效果的,这样可以保证目标对象的所有方法都能被代理而不依赖与接口;

GBLIB代理的主要API就是Enhancer类。

  • Enhancer:

public static Object newProxyInstance(ClassLoader loader, Class[] interfaces, InvocationHandler h) 作用:生成一个代理对象

loader

和目标对象一类的类加载器

interfaces

目标对象所有实现的接口的字节码对象

h

是一个接口,传一个匿名内部类做为实现类,并且重写其中的方法来实现代理的功能

返回值

返回代理对象

  • 示例代码:
package com.pattern.demo01;

import org.springframework.cglib.proxy.Enhancer;
import org.springframework.cglib.proxy.MethodInterceptor;
import org.springframework.cglib.proxy.MethodProxy;

import java.lang.reflect.Method;

/**
* @author lscl
* @version 1.0
* @intro:
*/
public class Demo03_CGLIB动态代理 {
public static void main(String[] args) {

Class<HouseOwner> targetClass = HouseOwner.class;

MethodInterceptor methodInterceptor = new MethodInterceptor() {
/**
* 代理对象执行的所有方法都会执行intercept方法
* @param proxy: 代理对象
* @param method: 代理的方法(目标对象的方法)
* @param args: 代理对象在执行方法时传递的参数
* @param methodProxy: 代理对象的方法对象(代理对象的方法)
* @return
* @throws Throwable
*/
@Override
public Object intercept(Object proxy, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {

String methodName = methodProxy.getSignature().getName();
System.out.println("执行的方法是: " + methodName);

// Object returnVal = method.invoke(new HouseOwner(), args);

// 等价于上面
Object returnVal = methodProxy.invokeSuper(proxy, args);
return returnVal;
}
};

// 使用CGLIB代理的类与目标对象是父子关系
HouseOwner proxy = (HouseOwner) Enhancer.create(targetClass, methodInterceptor);

proxy.riverViewRoom();
}
}

8.3.4 JDK代理和GBLIB代理的区别

  • JDK代理:
  • 1)针对于接口代理,该代理类实现了真实对象实现的所有方法
  • 2)代理出来的代理类和真实对象属于兄弟关系
  • CGLIB代理:
  • 1)针对于类进行代理,代理类继承了真实对象的所有方法(真实对象不能被final修饰);
  • 2)代理出来的代理与真实对象属于父子关系;

8.4 代理设计模式优缺点

  • 优点
  • 1)动态代理可以保护真实对象,也可以对真实对象进行增强;
  • 2)动态代理通过运行时生成代码的方式,取消了对真实对象的扩展限制,遵循开闭原则;
  • 缺点:
  • 1)代理模式造成系统中的类增多
  • 2)增加了系统的复杂度


标签:真实,对象,08,代理,设计模式,方法,public
From: https://blog.51cto.com/u_15919174/5959183

相关文章

  • 09【享元设计模式】
    九、享元设计模式9.1享元设计模式简介9.1.1享元设计模式概述享元模式(FlyweightPattern):享元模式主要的任务就是减少对象创建的数量,其宗旨是共享细粒度的对象,将多个对同一......
  • Web集群案例实战 -- Nginx 反向代理 -- 案例实战
    Nginx反向代理--案例实战​​前言​​前言本环境是基于Centos7.8系统构建Nginx学习环境具体构建,请参考​​Nginx-1.18.0环境部署​​环境准备rolehostipnginx-vers......
  • 设计模式-责任链模式
    概念责任链模式是一种行为设计模式就是将一个东西(入参)按步骤顺序处理每一个步骤(一个个实际处理入参的对象:可以抽出公共的接口或抽象类)对应相应的处理方式东西通过......
  • Jenkins实践指南-08-Jenkins 凭证管理
    4.Jenkins凭证管理  [作者:Surpassme]随着网络环境的变化,如果在Jenkins中使用明文密码会造成一些安全隐患。为此Jenkins也提供凭证管理功能,本章节来系统学习一下。4......
  • 设计模式,mvc,mvp,mvvm
    mvcmodel模型-视图view-控制器controller视图可以直接访问模型,所以视图里面包括模型信息,mvc关注的是模型不变,所以在mvc中,模型不依赖视图,但是view是依赖model的原理:模......
  • iOS监听模式系列之关于delegate(代理,委托)的学习
    其次,我简单的总结了一下自己用到的委托的作用有两个,一个是传值,一个是传事件。1.所谓传值经常用在b类要把自己的一个数据或者对象传给a类,让a类去展示或者处理。(切......
  • 安装confluence7.19.4、jira9.4破解并使用Nginx代理
    背景略安装jira准备两个目录,一个是jira的安装目录,一个是jira的home目录,数据都存在home目录/data/jira/data/jira_home下载,解压wgethttps://product-downl......
  • 使用HTTP代理之后仍显示本地 IP ,有推荐靠谱的HTTP代理厂商吗?
    是不是高匿,主要还是看HTTP_X_FORWARDED_FOR的参数是什么样的,我们也可以从这里来判断自己使用的HTTP代理是不是高匿。高匿代理:HTTP_X_FORWARDED_FOR=RandomIP address普匿代......
  • 设计模式之六大原则
    关于设计模式的六大设计原则的资料网上很多,但是很多地方解释地都太过于笼统化,我也找了很多资料来看,发现CSDN上有几篇关于设计模式的六大原则讲述的比较通俗易懂,因此转载过来......
  • java中的模板设计模式【抽象类的最佳实践】
    本文主要讲述抽象类最佳实践,模板设计模式。老韩的介绍:示例代码如下:1/**2*需求:计算出执行一个job()方法,所需要花费的时间.3*使用模板设计模式【抽......