博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
设计模式12---设计模式之代理模式(Proxy)(结构型)
阅读量:7087 次
发布时间:2019-06-28

本文共 9065 字,大约阅读时间需要 30 分钟。

1.场景模拟

考虑这样一个实际应用:

HR提出,当选择一个部门或者是分公司的时候,要把所有的分公司下的员工显示出来,而且不要翻页,方便进行业务处理,只需要显示姓名即可,但是点击姓名会出现这位员工的详细信息。

2.不用模式解决

数据库代码就不写了,总的来说就是用户表和部门表

直接上java代码

2.1.描述用户数据的对象

package demo10.proxy.example1;/** * 描述用户数据的对象 */public class UserModel {		/**	 * 用户编号	 */	private String userId;	/**	 * 用户姓名	 */	private String name;	/**	 * 部门编号	 */	private String depId;	/**	 * 性别	 */	private String sex;		public String getUserId() {		return userId;	}	public void setUserId(String userId) {		this.userId = userId;	}	public String getName() {		return name;	}	public void setName(String name) {		this.name = name;	}	public String getDepId() {		return depId;	}	public void setDepId(String depId) {		this.depId = depId;	}	public String getSex() {		return sex;	}	public void setSex(String sex) {		this.sex = sex;	}		@Override	public String toString(){		return "userId="+userId+",name="+name+",depId="+depId+",sex="+sex+"\n";	}}

2.2.实现示例要求的功能

package demo10.proxy.example1;import java.sql.Connection;import java.sql.DriverManager;import java.sql.PreparedStatement;import java.sql.ResultSet;import java.util.ArrayList;import java.util.Collection;/** * 实现示例要求的功能 */public class UserManager {	/**	 * 根据部门编号来获取该部门下的所有人员	 * 	 * @param depId	 *        部门编号	 * @return 该部门下的所有人员	 */	public Collection
getUserByDepId(String depId) throws Exception { Collection
col = new ArrayList
(); Connection conn = null; try { conn = this.getConnection(); String sql = "select * from tbl_user u,tbl_dep d " + "where u.depId=d.depId and d.depId like ?"; PreparedStatement pstmt = conn.prepareStatement(sql); pstmt.setString(1, depId + "%"); ResultSet rs = pstmt.executeQuery(); while (rs.next()) { UserModel um = new UserModel(); um.setUserId(rs.getString("userId")); um.setName(rs.getString("name")); um.setDepId(rs.getString("depId")); um.setSex(rs.getString("sex")); col.add(um); } rs.close(); pstmt.close(); } finally { conn.close(); } return col; } /** * 获取与数据库的连接 * * @return 数据库连接 */ private Connection getConnection() throws Exception { Class.forName("oracle.jdbc.driver.OracleDriver"); return DriverManager.getConnection("jdbc:oracle:thin:@localhost:1521:orcl", "test", "test"); }}

2.3.客户端

package demo10.proxy.example1;import java.util.*;public class Client {	public static void main(String[] args) throws Exception{		UserManager userManager = new UserManager();		Collection
col = userManager.getUserByDepId("0101"); System.out.println(col); }}

3.问题所在

当一次性访问的数据条数过多,并且每条数据的数据量又很大的情况下,就会消耗较多的内存。那么如何解决这个问题呢?

4.使用代理模式解决

4.1问题思考

其实很简单,我们开始时候只要进行名字的显示,点击名字以后才会进入详细信息,所以,我们可以在之间加一个代理,专门负责控制对某条数据的访问,当点击名字以后,再重新查询一下数据库即可,实际上就是以时间换空间的策略。

4.2代理模式的结构和说明

4.3代理模式示例代码

package demo10.proxy.example2;/** * 抽象的目标接口,定义具体的目标对象和代理公用的接口 */public interface Subject {	/**	 * 示意方法:一个抽象的请求方法	 */	public void request();}package demo10.proxy.example2;/** * 具体的目标对象,是真正被代理的对象 */public class RealSubject implements Subject{	public void request() {		//执行具体的功能处理	}}package demo10.proxy.example2;/** * 代理对象 */public class Proxy implements Subject{	/**	 * 持有被代理的具体的目标对象	 */	private RealSubject realSubject=null;	/**	 * 构造方法,传入被代理的具体的目标对象	 * @param realSubject 被代理的具体的目标对象	 */	public Proxy(RealSubject realSubject){		this.realSubject = realSubject;	}		public void request() {		//在转调具体的目标对象前,可以执行一些功能处理				//转调具体的目标对象的方法		realSubject.request();				//在转调具体的目标对象后,可以执行一些功能处理	}}

5.使用代理模式重写示例

5.1定义用户数据对象的接口

package demo10.proxy.example3;/** * 定义用户数据对象的接口 */public interface UserModelApi {	public String getUserId();	public void setUserId(String userId);	public String getName();	public void setName(String name);	public String getDepId();	public void setDepId(String depId);	public String getSex();	public void setSex(String sex);}

5.2描述用户数据的对象,没有什么变化

package demo10.proxy.example3;/** * 描述用户数据的对象 */public class UserModel implements UserModelApi{		/**	 * 用户编号	 */	private String userId;	/**	 * 用户姓名	 */	private String name;	/**	 * 部门编号	 */	private String depId;	/**	 * 性别	 */	private String sex;		public String getUserId() {		return userId;	}	public void setUserId(String userId) {		this.userId = userId;	}	public String getName() {		return name;	}	public void setName(String name) {		this.name = name;	}	public String getDepId() {		return depId;	}	public void setDepId(String depId) {		this.depId = depId;	}	public String getSex() {		return sex;	}	public void setSex(String sex) {		this.sex = sex;	}		@Override	public String toString(){		return "userId="+userId+",name="+name+",depId="+depId+",sex="+sex+"\n";	}}

5.3代理对象,代理用户数据对象

package demo10.proxy.example3;import java.sql.Connection;import java.sql.DriverManager;import java.sql.PreparedStatement;import java.sql.ResultSet;import java.sql.SQLException;/** * 代理对象,代理用户数据对象 */public class Proxy implements UserModelApi {	/**	 * 持有被代理的具体的目标对象	 */	private UserModel realSubject = null;	/**	 * 构造方法,传入被代理的具体的目标对象	 * 	 * @param realSubject	 *        被代理的具体的目标对象	 */	public Proxy(UserModel realSubject) {		this.realSubject = realSubject;	}	/**	 * 标示是否已经重新装载过数据了	 */	private boolean loaded = false;	public String getUserId() {		return realSubject.getUserId();	}	public void setUserId(String userId) {		realSubject.setUserId(userId);	}	public String getName() {		return realSubject.getName();	}	public void setName(String name) {		realSubject.setName(name);	}	public void setDepId(String depId) {		realSubject.setDepId(depId);	}	public void setSex(String sex) {		realSubject.setSex(sex);	}	public String getDepId() {		// 需要判断是否已经装载过了		if (!this.loaded) {			// 从数据库中重新装载			reload();			// 设置重新装载的标志为true			this.loaded = true;		}		return realSubject.getDepId();	}	public String getSex() {		if (!this.loaded) {			reload();			this.loaded = true;		}		return realSubject.getSex();	}	/**	 * 重新查询数据库以获取完整的用户数据	 */	private void reload() {		System.out.println("重新查询数据库获取完整的用户数据,userId==" + realSubject.getUserId());		Connection conn = null;		try {			conn = this.getConnection();			String sql = "select * from tbl_user where userId=? ";			PreparedStatement pstmt = conn.prepareStatement(sql);			pstmt.setString(1, realSubject.getUserId());			ResultSet rs = pstmt.executeQuery();			if (rs.next()) {				// 只需要重新获取除了userId和name外的数据				realSubject.setDepId(rs.getString("depId"));				realSubject.setSex(rs.getString("sex"));			}			rs.close();			pstmt.close();		} catch (Exception err) {			err.printStackTrace();		} finally {			try {				conn.close();			} catch (SQLException e) {				e.printStackTrace();			}		}	}	public String toString() {		return "userId=" + getUserId() + ",name=" + getName() + ",depId=" + getDepId() + ",sex=" + getSex() + "\n";	}	private Connection getConnection() throws Exception {		Class.forName("oracle.jdbc.driver.OracleDriver");		return DriverManager.getConnection("jdbc:oracle:thin:@localhost:1521:orcl", "test", "test");	}}

5.4实现示例要求的功能

package demo10.proxy.example3;import java.sql.Connection;import java.sql.DriverManager;import java.sql.PreparedStatement;import java.sql.ResultSet;import java.util.ArrayList;import java.util.Collection;/** * 实现示例要求的功能 */public class UserManager {	/**	 * 根据部门编号来获取该部门下的所有人员	 * 	 * @param depId	 *        部门编号	 * @return 该部门下的所有人员	 */	public Collection
getUserByDepId(String depId) throws Exception { Collection
col = new ArrayList
(); Connection conn = null; try { conn = this.getConnection(); // 只需要查询userId和name两个值就可以了 String sql = "select u.userId,u.name " + "from tbl_user u,tbl_dep d " + "where u.depId=d.depId and d.depId like ?"; PreparedStatement pstmt = conn.prepareStatement(sql); pstmt.setString(1, depId + "%"); ResultSet rs = pstmt.executeQuery(); while (rs.next()) { // 这里是创建的代理对象,而不是直接创建UserModel的对象 Proxy proxy = new Proxy(new UserModel()); // 只是设置userId和name两个值就可以了 proxy.setUserId(rs.getString("userId")); proxy.setName(rs.getString("name")); col.add(proxy); } rs.close(); pstmt.close(); } finally { conn.close(); } return col; } /** * 获取与数据库的连接 * * @return 数据库连接 */ private Connection getConnection() throws Exception { Class.forName("oracle.jdbc.driver.OracleDriver"); return DriverManager.getConnection("jdbc:oracle:thin:@localhost:1521:orcl", "test", "test"); }}

5.5客户端测试

package demo10.proxy.example3;import java.util.*;public class Client {	public static void main(String[] args) throws Exception{		UserManager userManager = new UserManager();		Collection
col = userManager.getUserByDepId("0101"); //如果只是显示用户名称,那么不需要重新查询数据库 for(UserModelApi umApi : col){ System.out.println("用户编号:="+umApi.getUserId()+",用户姓名:="+umApi.getName()); } //如果访问非用户编号和用户姓名外的属性,那就会重新查询数据库 for(UserModelApi umApi : col){ System.out.println("用户编号:="+umApi.getUserId()+",用户姓名:="+umApi.getName()+",所属部门:="+umApi.getDepId()); } }}

6.模式讲解

6.1认识代理模式

代理模式是通过创建一个代理对象,用这个代理去代表真实的对象,客户端得到这个对象以后,对客户端没有什么影响,就跟得到了真实的对象一样。当客户端操作这个代理对象时候,实际上功能还是由真实的对象来完成,只不过是通过代理来操作的,也就是客户端操作代理,代理操作真正的对象。

6.2代理模式调用示意图

 

6.3思考代理模式

代理模式的本质是:控制对象访问

代理模式通过代理目标对象,把代理对象和插入到客户端和目标对象之间,从而为客户端和目标对象之间引入一定的间接性。这种模式适用于查询某个对象次数较少的情况下,否则会查询多至N+1次

你可能感兴趣的文章
1-4常用路由协议的梳理
查看>>
Javascript核心
查看>>
利用UltraISO制作RedhatU盘启动盘
查看>>
一分钟教你快速建立起MySQL/Mariadb 主从状态检测脚本(shell)
查看>>
hive函数 -- regexp_extract
查看>>
C# vs2010 调用webservice
查看>>
Samba用户管理机制
查看>>
解决securecrt连接centos使用VIM编辑中文时乱码
查看>>
Windows server 2008R2域的安装和访问
查看>>
spring boot简单实现rest服务
查看>>
linux内核编译安装
查看>>
在CentOS/RHEL/Scientific Linux 6 & 7 上安装Telnet
查看>>
linux中hash命令:显示、添加或清除哈希表
查看>>
理解MySQL复制(Replication)——经典文献
查看>>
安卓手机recovery下刷补丁提示:“can't open /sdcard/update.zip(bad)”
查看>>
shared_ptr源码分析
查看>>
AOJ 2164 Revenge of the Round Table 题解《挑战程序设计竞赛》
查看>>
What's new in JSF 2.2
查看>>
eclipse 一直buildingWorkSpace 卡死解决
查看>>
Hyper-V导入Ubuntu虚拟机后发现网卡eth0丢失的解决办法
查看>>