11.1 场景问题
11.1.1 访问多条数据
考虑这样一个实际应用:要一次性访问多条数据。
这个功能的背景是这样的;在一个HR(人力资源)应用项目中客户提出,当选择一个部门或是分公司的时候,要把这个部门或者分公司下的所有员工都显示出来,而且不要翻页,好方便他们进行业务处理。在显示全部员工的时候,只需要显示名称即可,但是也需要提供如下的功能:在必要的时候可以选择并查看某位员工的详细信息。
客户方是一个集团公司,有些部门或者分公司可能有好几百人,不让翻页,也就是要求一次性的获取这多条数据并展示出来。
该怎么样实现呢?
11.1.2 不用模式的解决方案
不就是要获取某个部门或者某个分公司下的所有员工的信息吗?直接使用sql语句从数据库中查询就可以得到,示意性的SQL大致如下:
String sql = "select * from 用户表,部门表 " +"where 用户表.depId=部门表.depId " +"and 部门表.depId like '"+用户选择查看的depId+"%'"; |
为了方便获取某个部门或者某个分公司下的所有员工的信息,设计部门编号的时候,是按照层级来进行编码的,比如:上一级部门的编码为“01”,那么本级的编码就是“0101”、“0102”……以此类推,下一级的编码就是“010101”、“010102”……。
这种设计方式,从设计上看虽然不够优雅,但是实用,像这种获取某个部门或者某个分公司下的所有员工的信息的功能,就不用递归去查找了,直接使用like,只要找到以该编号开头的所有部门就可以了。
示例涉及到的表有两个,一个是用户表,一个是部门表。两个表需要描述的字段都较多,尤其是用户表,多达好几十个,为了示例简洁,简化后简单的定义如下:
DROP TABLE TBL_USER CASCADE CONSTRAINTS ; DROP TABLE TBL_DEP CASCADE CONSTRAINTS ;
CREATE TABLE TBL_DEP ( DEPID VARCHAR2(20) PRIMARY KEY, NAME VARCHAR2(20) ); CREATE TABLE TBL_USER ( USERID VARCHAR2(20) PRIMARY KEY, NAME VARCHAR2(20) , DEPID VARCHAR2(20) , SEX VARCHAR2(10) , CONSTRAINT TBL_USER_FK FOREIGN KEY(DEPID) REFERENCES TBL_DEP(DEPID) ); |
全部采用大写,是基于Oracle开发的习惯。再来增加点测试数据,SQL如下:
INSERT INTO TBL_DEP VALUES('01','总公司'); INSERT INTO TBL_DEP VALUES('0101','一分公司'); INSERT INTO TBL_DEP VALUES('0102','二分公司'); INSERT INTO TBL_DEP VALUES('010101','开发部'); INSERT INTO TBL_DEP VALUES('010102','测试部'); INSERT INTO TBL_DEP VALUES('010201','开发部'); INSERT INTO TBL_DEP VALUES('010202','客服部'); INSERT INTO TBL_USER VALUES('user0001','张三1','010101','男'); INSERT INTO TBL_USER VALUES('user0002','张三2','010101','男'); INSERT INTO TBL_USER VALUES('user0003','张三3','010102','男'); INSERT INTO TBL_USER VALUES('user0004','张三4','010201','男'); INSERT INTO TBL_USER VALUES('user0005','张三5','010201','男'); INSERT INTO TBL_USER VALUES('user0006','张三6','010202','男'); COMMIT; |
准备好了表结构和测试数据,下面来看看具体的实现示例,为了示例的简洁,直接使用JDBC来完成。
(1)先来定义描述用户数据的对象,示例代码如下:
/** * 描述用户数据的对象 */ 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; } public String toString(){ return "userId="+userId+",name="+name+",depId=" +depId+",sex="+sex+"\n"; } } |
(2)接下来使用JDBC来实现要求的功能,示例代码如下:
/** * 实现示例要求的功能 */ 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("你用的数据库对应的JDBC驱动类"); return DriverManager.getConnection( "连接数据库的URL", "用户名", "密码"); } } |
(3)写个客户端来测试看看,是否能满足功能要求,示例代码如下:
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); } } |
运行结果如下:
[userId=user0001,name=张三1,depId=010101,sex=男 , userId=user0002,name=张三2,depId=010101,sex=男 , userId=user0003,name=张三3,depId=010102,sex=男 ] |
你还可以修改getUserByDepId的参数,试试传递不同的参数,然后再看看输出的值,看看是否正确的实现了要求的功能。
11.1.3 有何问题
上面的实现看起来很简单,功能也正确,但是蕴含一个较大的问题,那就是:当一次性访问的数据条数过多,而且每条描述的数据量又很大的话,那会消耗较多的内存。
前面也说了,对于用户表,事实上是有很多字段的,不仅仅是示例的那么几个,再加上不使用翻页,一次性访问的数据就可能会有很多条。如果一次性需要访问的数据较多的话,内存开销会比较大。
但是从客户使用角度来说,有很大的随机性,客户既可能访问每一条数据,也可能一条都不访问。也就是说,一次性访问很多条数据,消耗了大量内存,但是很可能是浪费掉了,客户根本就不会去访问那么多数据,对于每条数据,客户只需要看看姓名而已。
那么该怎么实现,才能既把多条用户数据的姓名显示出来,而又能节省内存空间,当然还要实现在客户想要看到更多数据的时候,能正确访问到数据呢
相关推荐
适配器模式、装饰模式和代理模式 本文将详细介绍适配器模式、装饰模式和代理模式的概念、特点和应用场景,并通过实际的例子来阐述这三种模式的差异和相同点。 一、适配器模式 适配器模式是一种结构型设计模式,它...
代理模式是一种设计模式,它允许我们在不修改原始类(被代理类)的代码情况下,通过引入一个新的代理类来扩展或增强原始类的功能。这个代理类扮演着原始类的替身,它提供了与原始类相同的接口,但可以在调用原始方法...
代理模式是一种设计模式,它允许我们为一个对象创建一个代理对象,从而在客户端与目标对象之间插入一层间接性。这层间接性提供了多种优势,包括但不限于远程访问、延迟加载、安全控制、性能优化等。代理模式的核心...
代理模式是一种设计模式,它允许我们在访问某个对象时,通过一个代理对象来进行操作,从而实现对目标对象的控制、增强或优化。代理模式的核心在于创建一个代理类,该类作为真实对象的替代品,可以执行额外的任务,如...
1. 原始对象(Real Subject):这个角色负责实现业务逻辑,它是代理模式的核心。在示例程序中,可能有一个类实现了特定的功能,比如处理数据请求或执行计算。 2. 代理对象(Proxy):代理对象实现了与原始对象相同...
代理模式是一种常用的设计模式,它在软件开发中扮演着重要的角色,特别是在iOS平台的应用程序设计中。代理模式的核心思想是为一个对象提供一个替身或代理,以控制对这个对象的访问。这种模式允许我们通过代理来间接...
代理模式是设计模式的一种,它提供了一种对目标对象进行增强或者控制访问的方式。在本实例中,我们将深入探讨Java中的代理模式及其应用。 代理模式的核心思想是为一个对象创建一个代理对象,这个代理对象在客户端和...
1. **真实对象(Real Subject)**:这是代理模式要代理的目标对象,它实现了与代理对象相同的接口,使得代理对象可以代替它进行工作。 2. **代理对象(Proxy)**:代理对象持有真实对象的引用,并提供与真实对象相同...
**设计模式之代理模式(Proxy Pattern)** 设计模式是软件工程中的一种最佳实践,它是在特定情境下解决常见问题的模板。代理模式是其中一种行为设计模式,它的核心思想是为一个对象提供一个替身或者代理,以控制对...
**设计模式实现——代理模式** 在软件工程中,设计模式是一种通用可重用的解决方案,它描述了在特定上下文中经常出现的问题以及该问题的解决方案。代理模式是设计模式的一种,它提供了一种对目标对象的间接访问方式...
public void visit() {代理类class ProxySubject implements Subject {public void visit
在这个“Java设计模式-代理模式例子”中,我们将深入探讨代理模式的概念、实现方式以及它在实际开发中的应用。 代理模式的核心思想是为一个对象提供一个替身,这个替身即代理对象,代理对象控制对原对象的访问。在...
**Java设计模式——代理模式详解** 代理模式是软件设计模式中的一个重要组成部分,它在Java编程中扮演着举足轻重的角色。代理模式的核心思想是为一个对象提供一个替身,这个替身即代理对象,代理对象可以控制对原...
静态代理静态代理中,我们对目标对象的每个方法的增强都是手动完成的,从 JVM 层面来说, 静态代理在编译时就将接口、实现类、代理类这些都变成了一个个实际的 cl
在这种情况下,代理通常会为客户端提供相同的接口,并添加一个间接级别以支持对目标对象的受控访问,以避免对目标对象施加不适当的压力。在处理大量网络请求的应用程序时,
代理模式是设计模式的一种,它的主要目的是在不改变原有对象的基础上,为一个对象提供额外的功能或者控制对这个对象的访问。在Android开发中,代理模式的应用尤为常见,尤其在处理复杂的业务逻辑、网络请求、界面...