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. js jsp 时间 日期 控件 插件 简单 实用

    js时间控件一般都是找网上的用,这东西平常很少涉及到,一用到找起来却烦死人,不是没用就是太复杂,今天向大家推荐一个简单实用的控件,该控件在不断更新,而且有专门的网站对它进行维护,所以值得一看. 先说它 ...

  2. BUG出现的地方真的令我这个测试新人想象不到

    今天上班,仍然在等待下一阶段项目的研发完成. 没有正式测试任务的我,作为新手肯定要趁着这个时间好好学习了,偶尔再拿出公司已经上线发布的APP来到处看看. 就在这偶尔的情况下让我发现了一个在正式测试时根 ...

  3. Android 自定义UI--指南针

    有了之前的基础,下面开始实现一个简单的指南针.首先来看一下效果图, 我们可以粗略将这个指南针分为三个部分,一是圆形背景,二是刻度,三是文本.那么在写代码的时候,就可以声明三个Paint画笔来画以上三个 ...

  4. Tomcat 原理篇

    TOMCAT 原理篇一.Tomcat 组成(Tomcat 由以下组件组成) 1.server a) Server是一个Catalina Servlet容器: b) Server 可以包含一个或多个se ...

  5. 监控工具zabbix

    1 安装zabbixyum install -y epel-release安装rpm包的lamp环境 yum install  httpd mysql mysql-libs php php-mysql ...

  6. .net 调用Oracle.Data.Access 组件提供的用于批量操作的方法—获取数据库表结构方法和跟参数赋值方法

    1./// <summary> /// 获取当前目标表结构 /// </summary> /// <param name="tableName"> ...

  7. 如何在Silverlight应用程序中获取ASP.NET页面参数

    asp.net Silverlight应用程序中获取载体aspx页面参数 有时候SL应用中需要使用由aspx页面中传递过来的参数值,此时通常有两种方法获取 1. 使用InitParameters属性, ...

  8. C# 窗体程序入门 之计算器

    之前一直在java的B/S,这次被要求做一个C/S,其中客户端主要是界面和socket通信.因为没有使用过C#和Visual Studio的控件编程,先来个HelloWorld. 我的环境是visua ...

  9. C++中的函数指针用法

    代码: #include <iostream> #include <cstdio> typedef void (*FUN)(); using namespace std; vo ...

  10. Mysql学习(慕课学习笔记1)启动、登录及常用命令

    Mysql学习 启动数据库服务 net start mysql    (不能加分号!!!!) 关闭数据库服务 net stop mysql 登录数据库 mysql -uroot -p -P3306 - ...