zoukankan      html  css  js  c++  java
  • 设计模式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+"
    ";
    	}
    }

    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+"
    ";
    	}
    }

    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() + "
    ";
    	}
    
    
    	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次

  • 相关阅读:
    get请求数据
    ajax (详细)
    DedeCMS去掉友情链接中“织梦链投放”“织梦链”的方法
    Metro UI CSS可以快速创建一个Windows 8风格的网站
    CSS实现垂直居中的5种方法
    解决jQuery冲突 noConflict
    dedecms pic_scroll.js和jquery-1.9.1.min.js
    js和jquery下拉菜单全攻略
    IE6、IE7、IE8、FireFox css line-height兼容问题
    IE开发利器-IE10中的F12开发者工具
  • 原文地址:https://www.cnblogs.com/dyllove98/p/3220129.html
Copyright © 2011-2022 走看看