java设计模式6——代理模式
java设计模式6——代理模式
1、代理模式介绍:
1.1、为什么要学习代理模式?因为这就是Spring Aop的底层!(SpringAop 和 SpringMvc)
1.2、代理模式的分类:
- 静态代理
- 动态代理
1.3、代理模式关系图(以租房子为例)
2、静态代理
2.1、角色分析:
- 抽象角色:一般会使用接口或者抽象类来解决
- 真实角色:被代理的角色
- 代理客户:代理真实角色。代理真实角色后,我们一般会做一些附属的操作
- 客户:访问代理对象的人
2.2、例1(租房子演示)
2.2.1、抽象角色实现(房东抽象类)
package com.xgp.company.结构性模式.代理模式.静态代理.Demo1;
/**
- 租房
*/
public interface Rent {
void rent();
}
2.2.2、真实角色实现(房东的实现类)
package com.xgp.company.结构性模式.代理模式.静态代理.Demo1;
/**
- 房东
*/
public class Host implements Rent {
@Override
public void rent() {
System.out.println("房东要出租房子!");
}
}
2.2.3、不通过代理进行租房
package com.xgp.company.结构性模式.代理模式.静态代理.Demo1;
public class Client {
public static void main(String[] args) {
//直接找房东
Host host = new Host();
host.rent();
}
}
运行结果:
房东要出租房子!
2.2.4、弊端
- 在实际的生活场景中,房东可能只卖房,而不负责租房
- 如果要提高租房子的成功率,必然还需要一些其他的服务,如:看房、谈价钱、签合同等,而这些房东并不想参与,因此产生了中介,也就是代理。
2.2.5、代理出现
package com.xgp.company.结构性模式.代理模式.静态代理.Demo1;
public class Proxy implements Rent {
private Host host;
public Proxy() {
}
public Proxy(Host host) {
this.host = host;
}
@Override
public void rent() {
seeHouse();
host.rent();
fare();
hetong();
}
//看房
public void seeHouse() {
System.out.println("中介代理看房");
}
//收中介费
public void fare() {
System.out.println("收中介费");
}
public void hetong() {
System.out.println("签合同");
}
}
2.2.6、通过代理来租房子
package com.xgp.company.结构性模式.代理模式.静态代理.Demo1;
public class Client {
public static void main(String[] args) {
/* //直接找房东
Host host = new Host();
host.rent();*/
//通过代理去租房子
//房东要租房子
Host host = new Host();
//代理
//中介帮房东租房子,但是,中介一半都会有一些附属操作
Proxy proxy = new Proxy(host);
proxy.rent();
}
}
运行结果:
中介代理看房
房东要出租房子!
收中介费
签合同
2.3、分析:
代理模式的好处
- 可以使真实角色的操作更加纯粹,不用去关注一些公共的业务。
- 公共的业务交给了代理角色去完成,实现了业务的分工。
- 公共业务发生扩展的时候,方便集中管理。
缺点:
- 一个真实角色就会产生一个代理的角色,代码量翻倍,开发效率变低。
2.4、例1(增删改查业务的演示)
2.4.1、编写service的抽象类
package com.xgp.company.结构性模式.代理模式.静态代理.Demo2;
public interface UserService {
void add();
void del();
void update();
void query();
}
2.4.2、编写service的实现类
package com.xgp.company.结构性模式.代理模式.静态代理.Demo2;
/**
- 真实对象
*/
public class UserServiceImpl implements UserService {
@Override
public void add() {
System.out.println("增加了一个用户");
}
@Override
public void del() {
System.out.println("删除了一个用户");
}
@Override
public void update() {
System.out.println("更新了一个用户");
}
@Override
public void query() {
System.out.println("查询了一个用户");
}
}
2.4.3、如果此时想不改变原有的代码,而增加方法日志打印的功能,此时代理诞生
package com.xgp.company.结构性模式.代理模式.静态代理.Demo2;
/**
- 代理角色,增加日志的功能
*/
public class UserServiceProxy implements UserService {
private UserService userService;
public void setUserService(UserService userService) {
this.userService = userService;
}
@Override
public void add() {
userService.add();
log("add");
}
@Override
public void del() {
userService.del();
log("del");
}
@Override
public void update() {
userService.update();
log("update");
}
@Override
public void query() {
userService.query();
log("query");
}
public void log(String msg) {
System.out.println("使用了" + msg + "方法!");
}
}
2.4.4、编写客户端类,使用service的方法,并打印日志
package com.xgp.company.结构性模式.代理模式.静态代理.Demo2;
public class Client {
public static void main(String[] args) {
UserService userService = new UserServiceImpl();
UserServiceProxy proxy = new UserServiceProxy();
proxy.setUserService(userService);
proxy.add();
proxy.del();
proxy.update();
proxy.query();
}
}
运行结果:
增加了一个用户
使用了add方法!
删除了一个用户
使用了del方法!
更新了一个用户
使用了update方法!
查询了一个用户
使用了query方法!
2.5、反思:在实际的业务中,横向开发的好处
可以保证原有代码的可行性,不会对软件原来的版本进行破坏,向过去兼容。
3、动态代理
3.1、动态代理的特点
- 动态代理和静态代理一样
- 动态代理的代理类是动态生成的,不是我们直接写的
3.2、动态代理实现方式的分类
- 基于接口——JDK动态代理(本节需要讲述的方式)
- 基于类:cglib
- java字节码实现:javasist
3.3、需要了解的两个类
- Proxy:代理类
- InvocationHandler:调用处理程序类
具体的使用参照java的api
3.4、例1——房东租房的例子
3.4.1、房东的接口和实现类不变
3.4.2、实现自动生成代理的类
package com.xgp.company.结构性模式.代理模式.动态代理.Demo1;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
/**
- 等下我们会用这个类,自动生成代理类
*/
public class ProxyInvocationHandler implements InvocationHandler {
/**
- 被代理的接口
*/
private Rent rent;
public void setRent(Rent rent) {
this.rent = rent;
}
/**
- 获得一个代理
- @return
*/
public Object getProxy() {
return Proxy.newProxyInstance(this.getClass().getClassLoader(),rent.getClass().getInterfaces(),this);
}
/**
- 处理代理实例,并放回结果
- @param proxy
- @param method
- @param args
- @return
- @throws Throwable
*/
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
//用反射来执行方法
seeHouse(); //调用代理自身的方法
//动态代理的本质,就是使用反射机制来实现
Object result = method.invoke(rent, args);
fare();
hetong();
return result;
}
public void seeHouse() {
System.out.println("中介带看房子!");
}
//收中介费
public void fare() {
System.out.println("收中介费");
}
public void hetong() {
System.out.println("签合同");
}
}
3.4.3、实现客户端使用代理来租房子
package com.xgp.company.结构性模式.代理模式.动态代理.Demo1;
public class Client {
public static void main(String[] args) {
//真实角色
Host host = new Host();
//代理角色
ProxyInvocationHandler pih = new ProxyInvocationHandler();
//通过调用程序处理角色,来处理我们要调用的接口对象
pih.setRent(host);
//放回代理类
//这里的代理类就是动态生成的,我们并没有写他
Rent proxy = (Rent) pih.getProxy();
proxy.rent();
}
}
运行结果:
中介带看房子!
房东要出租房子!
收中介费
签合同
3.5、例2——增删改查的例子
3.5.1、先来实现一个万能的代理生成类
package com.xgp.company.结构性模式.代理模式.动态代理.Demo2;
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;
}
/**
- 获得一个代理
- @return
*/
public Object getProxy() {
return Proxy.newProxyInstance(this.getClass().getClassLoader(),target.getClass().getInterfaces(),this);
}
/**
- 处理代理实例,并放回结果
- @param proxy
- @param method
- @param args
- @return
- @throws Throwable
*/
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
//用反射来执行方法
//动态代理的本质,就是使用反射机制来实现
Object result = method.invoke(target, args);
log(method.getName());
return result;
}
public void log(String msg) {
System.out.println("使用了" + msg + "方法!");
}
}
也就是将上一个例子的具体实现类——房东类,替换成Object类
3.5.2、UserService的接口和实现类不变
3.5.3、编写客户端类使用代理调用增删改查方法
package com.xgp.company.结构性模式.代理模式.动态代理.Demo2;
public class Client {
public static void main(String[] args) {
//真实角色
UserService userService = new UserServiceImpl();
//代理角色
ProxyInvocationHandler pih = new ProxyInvocationHandler();
pih.setTarget(userService);
UserService proxy = (UserService) pih.getProxy();
proxy.add();
proxy.del();
proxy.update();
proxy.query();
}
}
运行结果:
增加了一个用户
使用了add方法!
删除了一个用户
使用了del方法!
更新了一个用户
使用了update方法!
查询了一个用户
使用了query方法!
3.6、弊端分析:
虽然使用动态代理能够节省代码量,并且实现静态代理的全部优点。但是,动态代理的核心是反射技术,通过反射技术调用方法效率较大,因此也可能影响系统效率。
3.7、动态代理的好处
一个动态代理的是一个接口,一般就是对应的一类业务。
java设计模式6——代理模式的更多相关文章
- Java设计模式之代理模式(静态代理和JDK、CGLib动态代理)以及应用场景
我做了个例子 ,需要可以下载源码:代理模式 1.前言: Spring 的AOP 面向切面编程,是通过动态代理实现的, 由两部分组成:(a) 如果有接口的话 通过 JDK 接口级别的代理 (b) 如果没 ...
- 夜话JAVA设计模式之代理模式(Proxy)
代理模式定义:为另一个对象提供一个替身或者占位符以控制对这个对象的访问.---<Head First 设计模式> 代理模式换句话说就是给某一个对象创建一个代理对象,由这个代理对象控制对原对 ...
- Java设计模式:代理模式(转)
代理(Proxy)是一种设计模式,提供了对目标对象另外的访问方式;即通过代理对象访问目标对象.这样做的好处是:可以在目标对象实现的基础上,增强额外的功能操作,即扩展目标对象的功能.这里使用到编程中的一 ...
- Java 设计模式_代理模式(2016-08-19)
概念: 代理模式是对象的结构模式.代理模式给某一个对象提供一个代理对象,并由代理对象控制对原对象的引用. 就是一个人或者机构代表另一个人或者机构采取行动.在一些情况下,一个客户不想或者不能够直接引用一 ...
- JAVA设计模式:代理模式&& 装饰模式区别
在前面学习了代理模式和装饰模式后,发现对两者之间有时候会混淆,因此对两者进行了区别和理解: 装饰模式你可以这样理解,就像糖一样,卖的时候商家大多要在外面包一层糖纸,其实原本还是糖. public in ...
- Java设计模式:代理模式(二)
承接上文 三.计数代理 计数代理的应用场景是:当客户程序需要在调用服务提供者对象的方法之前或之后执行日志或者计数等额外功能时,就可以用到技术代理模式.计数代理模式并不是把额外操作的代码直接添加到原服务 ...
- java设计模式之代理模式 ,以及和java 回调机制的区别
java 代理模式就是: 将自己要做的事交给别人去做(这个别人就是代理者,自己就是被代理者),为什么自己能做的要交给别人去做了?假如一个小学生小明,现在要写作业,但是又想玩游戏,他更想玩游戏,并且不想 ...
- Java设计模式之代理模式(Proxy)
前言: 最近在研究Retrofit开源框架的时候,其主要核心代码是通过注解标示参数,动态代理模式实现具体接口,反射机制进行参数解析,最终实现发送请求.其实之前在学习Xutils源码的时候,Xutils ...
- Java设计模式 之 代理模式
所谓的代理模式就是为其它类或对象提供一个代理以控制对这个对象的访问.那么常见的代理有远程代理,虚拟代理,保护代理,智能代理. 1. 远程代理:为一个不同地址空间的对象提供一个本地代理对象. 2. 虚拟 ...
随机推荐
- LEFT函数使用
详解:LEFT函数用于从一个文本字符串的第一个字符开始返回指定个数的字符 1.提取A2单元格从左往右2位字符 2.函数使用用途: LEFT函数用于从一个文本字符串的第一个字符开始返回指定个数的字符 语 ...
- 基于Jenkins的持续交付全流程设计与实践
1 从理论开始 什么是DevOps? 近年来,随着DevOps理念的逐渐深入人心,企业逐渐意识到从看似重复的手工劳动中实现自动化流程处理,对于提高企业劳动生产力已经非常重要,尤其是面向互联网的开发者, ...
- 《图解机器学习-杉山将著》读书笔记---CH5
CH5 稀疏学习 重点提炼 提出稀疏学习的缘故: 虽然带有约束条件的最小二乘学习法结合交叉验证法,在实际应用中是非常有效的回归方法,但是,当参数特别多时,计算参数以及预测值需要大量时间.此时,我们要解 ...
- python切片(获取一个子列表(数组))
切片: 切片指从现有列表中,获取一个子列表 返回一个新列表,不影响原列表. 下标以 0 开始: list = ['红','绿','蓝','白','黑','黄','青']# 下标 0 1 2 3 4 5 ...
- 前端笔记6-js2
1.break 和continue用法 break结束本次循环,如果想结束外层循环,可以通过这个label来指定要结束的循环. continue可以用来跳过当次循环,如果想跳过外次循环,也可以通过这个 ...
- python中常⽤的excel模块库
python中常用的excel模块库&安装方法 openpyxl openpyxl是⼀个Python库,用于读取/写⼊Excel 2010 xlsx / xlsm / xltx / xltm⽂ ...
- 搞定SpringBoot多数据源(3):参数化变更源
目录 1. 引言 2. 参数化变更源说明 2.1 解决思路 2.2 流程说明 3. 实现参数化变更源 3.1 改造动态数据源 3.1.1 动态数据源添加功能 3.1.2 动态数据源配置 3.2 添加数 ...
- Java入门 - 面向对象 - 04.抽象类
原文地址:http://www.work100.net/training/java-abstract.html 更多教程:光束云 - 免费课程 抽象类 序号 文内章节 视频 1 概述 2 Java抽象 ...
- 将jar包安装到本地仓库
通过cmd切换到apache maven 的bin目录 mvn install:install-file -DgroupId=com.antgroup.zmxy -DartifactId=zmxy-s ...
- 彻底理解Future模式
先上一个场景:假如你突然想做饭,但是没有厨具,也没有食材.网上购买厨具比较方便,食材去超市买更放心. 实现分析:在快递员送厨具的期间,我们肯定不会闲着,可以去超市买食材.所以,在主线程里面另起一个子线 ...