设计模式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享元模式(结构型)
动机:采用纯粹对象方案的问题在于大量细粒度的对象会很快充斥在系统中,从而带来很高的运行代价——主要指内存需求方面的代价.如何在避免大量细粒度对象问题的同 时,让外部客户程序仍然能够透明地使用面向对象的 ...
随机推荐
- C# 异步和委托学习
IAsyncResult是接口: IAsyncResult 异步设计模式通过名为 BeginOperationName 和 EndOperationName 的两个方法来实现原同步方法的异步调用,如 ...
- .NET基础拾遗(4)委托为何而生?
生活中的例子: 你早上要吃包子作为早饭,那么你可能让你爸爸或者妈妈帮你做,那你就会调用 爸爸.要包子() 或妈妈.要包子() 返回包子对象. 但是如果你爸妈不在家的时候,你只能去街上买,问题是你根本不 ...
- EF数据存贮问题二之“无法定义这两个对象之间的关系,因为它们附加到不同的 ObjectContext 对象”
“无法定义这两个对象之间的关系,因为它们附加到不同的 ObjectContext 对象”,这是在EF中,一对多关系表,有外键的类保存至数据库中出现的错误. 我原来是用JAVA开发的,习惯性的处理一对多 ...
- SQL获取选中时间的交集
如上图:t1,t2代表要选择的时间段,t3,t4代表系统时间. 那么如果要获取选中时间段所有的交集为: 条件1 and ((t3>t1 and t1>t2) or (t3<t2 an ...
- Xcode快捷键 ---- 提高效率
Mac中主要有四个修饰键,分别是Command,Control,Option和Shift. 1. ⌘ + L 搜索行数,输入行数,调到指定行数 2.⌘ + shift + O 查询flie ...
- Java图片工具类,完成图片的截取和任意缩放
package com.common.util; import java.awt.Graphics2D; import java.awt.Image; import java.awt.Renderin ...
- BZOJ 3277 串 (广义后缀自动机)
3277: 串 Time Limit: 10 Sec Memory Limit: 128 MB Submit: 309 Solved: 118 [Submit][Status][Discuss] De ...
- Sherlock and GCD
1 import fractions, functools, sys if __name__ == '__main__': T = int(sys.stdin.readline()) for _ in ...
- Loadrunner根据PV量来确定需要进行压测的并发量
在实际做压力测试的过程中,我们有时不知道用怎样的并发量比较好,下面是几个用PV量去确定并发量的公式,这个在我们公司是比较适用的,大家可以根据自己的业务进行运算. 方法一:这个方法是我在网上查到的80- ...
- WordPress插件开发记录
1.a标签在新的网页中打开内容 <a href="网址" target="_blank"></a> 2.PDO的$re ...