设计模式12---设计模式之代理模式(Proxy)(结构型)
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<UserModel> getUserByDepId(String depId) throws Exception {
Collection<UserModel> col = new ArrayList<UserModel>();
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<UserModel> 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<UserModelApi> getUserByDepId(String depId) throws Exception {
Collection<UserModelApi> col = new ArrayList<UserModelApi>();
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<UserModelApi> 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次
设计模式12---设计模式之代理模式(Proxy)(结构型)的更多相关文章
- 设计模式12: Proxy 代理模式(结构型模式)
Proxy 代理模式(结构型模式) 直接与间接 人们对于复杂的软件系统常常有一种处理手法,即增加一层间接层,从而对系统获得一种更为灵活.满足特定需求的解决方案.如下图,开始时,A需要和B进行3次通信, ...
- 【转】设计模式(十一)代理模式Proxy(结构型)
设计模式(十一)代理模式Proxy(结构型) 1.概述 因为某个对象消耗太多资源,而且你的代码并不是每个逻辑路径都需要此对象, 你曾有过延迟创建对象的想法吗 ( if和else就是不同的两条逻辑路径) ...
- 设计模式10: Facade 外观模式(结构型模式)
Facade 外观模式(结构型模式) 系统的复杂度 假设我们要开发一个坦克模式系统用于模拟坦克车在各种作战环境中的行为,其中坦克系统由引擎.控制器.车轮.车身等各个子系统构成. internal cl ...
- 设计模式08: Composite 组合模式(结构型模式)
Composite 组合模式(结构型模式) 对象容器的问题在面向对象系统中,我们常会遇到一类具有“容器”特征的对象——即他们在充当对象的同时,又是其他对象的容器. public interface I ...
- 设计模式07: Bridge 桥接模式(结构型模式)
Bridge 桥接模式(结构型模式) 抽象与实现 抽象不应该依赖于实现细节,实现细节应该依赖于抽象. 抽象B稳定,实现细节b变化 问题在于如果抽象B由于固有的原因,本身并不稳定,也有可能变化,怎么办? ...
- 设计模式(十一)代理模式Proxy(结构型)
1.概述 因为某个对象消耗太多资源,而且你的代码并不是每个逻辑路径都需要此对象, 你曾有过延迟创建对象的想法吗 ( if和else就是不同的两条逻辑路径) ? 你有想过限制访问某个对象,也就是说,提供 ...
- 【设计模式 - 12】之代理模式(Proxy)
1 模式简介 1.1 定义 为其他对象提供一种代理以控制对这个对象的访问.代理对象起到中介作用,可以去掉功能服务或增加额外服务. 1.2 常见的代理模式 1) 远程 ...
- Java设计模式11:常用设计模式之代理模式(结构型模式)
1. Java之代理模式(Proxy Pattern) (1)概述: 代理模式的作用是:为其他对象提供一种代理以控制对这个对象的访问. 在某些情况下,一个客户不想或者不能直接引用另一个对象,而代理对象 ...
- 设计模式(四)——代理模式(Proxy)
代理模式的参与者有:一个约束.一个代理者.一个被代理者.一个调用者 代理模式的实现很简单:还是那个房子,对于开门这个操作,我更换了一个远程解锁的门,那么我就可以通过这个远程连接的服务器远程解锁,这样我 ...
- 面向对象设计模式之Flyweight享元模式(结构型)
动机:采用纯粹对象方案的问题在于大量细粒度的对象会很快充斥在系统中,从而带来很高的运行代价——主要指内存需求方面的代价.如何在避免大量细粒度对象问题的同 时,让外部客户程序仍然能够透明地使用面向对象的 ...
随机推荐
- jquery之批量上传图片
//var btn; /** * * 获取当前时间 */ ==================================js=================================== ...
- python-socket 粘包问题
解决粘包的问题: 1.服务端在发送数据之前,先把发送数据的长度告诉客户端,要发送多少数据,然后客户端根据这个数据的长度循环接收就OK 传输过程: 服务端: 1.send #数据长度 ...
- C#遍历Object各个属性含List泛型嵌套。
同事遇到一个问题:在做手机app接口时,返回JSON格式,json里面的数据属性均是string类型,但不能出现NULL(手机端那边说处理很麻烦,哎).Model已经创建好了,而且model的每个属性 ...
- UTF8转GB2312(UTF8解码)
小弟C++上手没多久,代码不严谨之处敬请见谅.英语也不是很好,有的是直接使用的拼音. string MyUTF_8toGB2312(string str) { ,,str.c_str(),-,NULL ...
- Android-图标
首先需要申明一点,系统图标并不存在于项目资源中,而是存在于设备中. 这就带来一个大问题,界面风格的控制权交到了不同的设备手中.这是我们不愿意看到的. 如何解决这个问题?有两种方法: 1.创建自己的图标 ...
- C#调用C++的DLL 数据类型转换
/C++中的DLL函数原型为 //extern "C" __declspec(dllexport) bool 方法名一(const char* 变量名1, unsig ...
- redis的备份和恢复
Redis 数据备份与恢复 数据备份 语法 redis Save 命令基本语法如下: redis > SAVE 实例 redis > SAVE OK 该命令将在 redis 备份目录中创建 ...
- QTP描述性编程中往WebEdit控件输入文字问题
在网上查找到许多相关的描述性编程的案例,自己就想动手一试,于是在专家视图中输入如下代码: systemUtil.Run "http://www.baidu.com" wait(15 ...
- C#操作Flash动画
对于在C#开发的过程中没有接触过Flash相关开发的人员来说,没有系统的资料进行学习,那么这篇文档针对于初学者来说是很好的学习DEMO. 本文章中的DEMO实现了C#的COM控件库中本来就带有对fla ...
- C++中的cout输出机制
代码: #include <iostream> using namespace std; int hello(){ cout<<"hello"<< ...