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)(结构型)的更多相关文章

  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. 设计模式(四)——代理模式(Proxy)

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

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

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

随机推荐

  1. Linux 常用系统命令-20160504

    一.显示目录和文件的命令 1.ls(list)  功能说明: 列出目录内容. 语 法 : ls [-1aAbBcCdDfFgGhHiklLmnNopqQrRsStuUvxX][-I < 范 本 ...

  2. CSS基础知识笔记(二)之选择器

    CSS选择器 选择器{ 样式; } 每一条css样式声明(定义)由两部分组成,形式如下: 在{}之前的部分就是“选择器”,“选择器”指明了{}中的“样式”的作用对象,也就是“样式”作用于网页中的哪些元 ...

  3. HTML基础知识笔记(三)

    HTML下拉列表框 讲解: 1.value: <option value="House Blend">House Blend</option> 2.sele ...

  4. 开始学javascript基础

    JavaScript非常值得我们学习. 1)所有主浏览器都支持JavaScript. 2) 目前,全世界大部分网页都使用JavaScript. 3) 它可以使网页呈现各种动态效果. 4)作为一个Web ...

  5. js获取当前页面的网址域名地址

    1.获取当前完整网址thisURL = document.URL;thisHREF = document.location.href;thisSLoc = self.location.href;thi ...

  6. 《第一行代码》学习笔记15-UI(4)

    1.ListView允许用户通过手指上下滑动的方式将屏幕外的数据滚动到屏幕内,同时屏幕上原有的数据则会滚动出屏幕. 2.数组中的数据无法直接传递给ListView,得借助适配器来完成.此处使用Arra ...

  7. JS 图片预览功能

    <script type="text/javascript">    function DisplayImage(fileTag) {        document. ...

  8. (一)backbone - API入门

    初探 backbone采用MVC模式,本身提供了模型.控制器和视图从而我们应用程序的骨架便形成. Backbone.js 唯一重度依赖 Underscore.js. 对于 RESTful , hist ...

  9. C/C++中的虚析构函数和私有析构函数的使用

    代码: #include <iostream> using namespace std; class A{ public: A(){ cout<<"construct ...

  10. UWP开发小记

    针对个人的上一篇文章中提到的遇到的几个问题,做一下个人解答 DLL部署的问题,可以将DLL添加到工程中,属性中设置content为true,这样,部署目录下就会有这个文件. 需要说明的是,这个文件确实 ...