设计模式12---设计模式之代理模式(Proxy)(结构型)

时间:2022-11-06 10:13:24

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代理模式的结构和说明

设计模式12---设计模式之代理模式(Proxy)(结构型)

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代理模式调用示意图

设计模式12---设计模式之代理模式(Proxy)(结构型)

6.3思考代理模式

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

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

设计模式12---设计模式之代理模式(Proxy)(结构型)的更多相关文章

  1. 设计模式12: Proxy 代理模式(结构型模式)

    Proxy 代理模式(结构型模式) 直接与间接 人们对于复杂的软件系统常常有一种处理手法,即增加一层间接层,从而对系统获得一种更为灵活.满足特定需求的解决方案.如下图,开始时,A需要和B进行3次通信, ...

  2. 【转】设计模式(十一)代理模式Proxy(结构型)

    设计模式(十一)代理模式Proxy(结构型) 1.概述 因为某个对象消耗太多资源,而且你的代码并不是每个逻辑路径都需要此对象, 你曾有过延迟创建对象的想法吗 ( if和else就是不同的两条逻辑路径) ...

  3. 设计模式10: Facade 外观模式(结构型模式)

    Facade 外观模式(结构型模式) 系统的复杂度 假设我们要开发一个坦克模式系统用于模拟坦克车在各种作战环境中的行为,其中坦克系统由引擎.控制器.车轮.车身等各个子系统构成. internal cl ...

  4. 设计模式08: Composite 组合模式(结构型模式)

    Composite 组合模式(结构型模式) 对象容器的问题在面向对象系统中,我们常会遇到一类具有“容器”特征的对象——即他们在充当对象的同时,又是其他对象的容器. public interface I ...

  5. 设计模式07: Bridge 桥接模式(结构型模式)

    Bridge 桥接模式(结构型模式) 抽象与实现 抽象不应该依赖于实现细节,实现细节应该依赖于抽象. 抽象B稳定,实现细节b变化 问题在于如果抽象B由于固有的原因,本身并不稳定,也有可能变化,怎么办? ...

  6. 设计模式(十一)代理模式Proxy(结构型)

    1.概述 因为某个对象消耗太多资源,而且你的代码并不是每个逻辑路径都需要此对象, 你曾有过延迟创建对象的想法吗 ( if和else就是不同的两条逻辑路径) ? 你有想过限制访问某个对象,也就是说,提供 ...

  7. 【设计模式 - 12】之代理模式(Proxy)

    1      模式简介 1.1    定义 为其他对象提供一种代理以控制对这个对象的访问.代理对象起到中介作用,可以去掉功能服务或增加额外服务. 1.2    常见的代理模式 1)        远程 ...

  8. Java设计模式11:常用设计模式之代理模式(结构型模式)

    1. Java之代理模式(Proxy Pattern) (1)概述: 代理模式的作用是:为其他对象提供一种代理以控制对这个对象的访问. 在某些情况下,一个客户不想或者不能直接引用另一个对象,而代理对象 ...

  9. 设计模式(四)——代理模式&lpar;Proxy&rpar;

    代理模式的参与者有:一个约束.一个代理者.一个被代理者.一个调用者 代理模式的实现很简单:还是那个房子,对于开门这个操作,我更换了一个远程解锁的门,那么我就可以通过这个远程连接的服务器远程解锁,这样我 ...

  10. 面向对象设计模式之Flyweight享元模式(结构型)

    动机:采用纯粹对象方案的问题在于大量细粒度的对象会很快充斥在系统中,从而带来很高的运行代价——主要指内存需求方面的代价.如何在避免大量细粒度对象问题的同 时,让外部客户程序仍然能够透明地使用面向对象的 ...

随机推荐

  1. CSS line-height与vertical-align&colon;baseline

    一.当line-height与vertical-align相遇,会发生很多匪夷所思的现象 首先,请看如下代码: <!DOCTYPE html> <html> <head& ...

  2. BT5 &amp&semi; Kali Linux 网卡选择

    [需要注意的几点]: 芯片类型 知否支持外接天线 网卡固件版本 支持的无线协议 网卡功率 BT5/Kali  RC3支持网卡: RTL8187, R8187 (Realtek) 功率高.兼容性好 Ra ...

  3. HDU-4518 吉哥系列故事——最终数 AC自动机&plus;数位DP

    题意:如果一个数中的某一段是长度大于2的菲波那契数,那么这个数就被定义为F数,前几个F数是13,21,34,55......将这些数字进行编号,a1 = 13, a2 = 21.现给定一个数n,输出和 ...

  4. Node调试工具JSHint

    Node调试工具JSHint的安装及配置教程 作者: 字体:[增加 减小] 类型:转载 时间:2014-05-27我要评论 Node的优势我就不再乱吹捧了,它让javascript统一web的前后台成 ...

  5. Team Foundation Server 2015使用教程--tfs用户账号切换

  6. JavaSE中常见的工具类

    Arrays 用来操作数组, 常用方法是 sort()和toString()方法 Iterator 我们常说的迭代器就是这哥们,专门用来操作集合元素的工具类 常用方法是: hasNex()t和next ...

  7. 数据结构系列(4)之 B 树

    本文将主要讲述另一种树形结构,B 树:B 树是一种多路平衡查找树,但是可以将其理解为是由二叉查找树合并而来:它主要用于在不同存储介质之间查找数据的时候,减少 I/O 次数(因为一次读一个节点,可以读取 ...

  8. 未知高度的div自适应图片高度

    <div style="background-image: url(http://your-image.jpg);"> <img src="http:/ ...

  9. 关于mysql自增主键

    对于mysql表(其他数据库没测试过) 如果定义了自增主键,并且手动设置了主键的值,那么当再次自增创建数据的时候,回在设置的主键值的基础上进行自增. 如(id是主键): 起始插入(3,1),而后手动插 ...

  10. POJ 2828 Buy Tickets(单点更新) 详细题解和思路

    题意:给n个人插队,输出最后的队伍情况(题意写的有些粗糙) 思路:第一点:在最后的队伍中,我们唯一能确定的是最后一个人一定能排到指定位置.那么,倒数第二个是在最后一个基础上确定位置的,这样一层一层的倒 ...