代理模式(Proxy)
来源:互联网 发布:小米6相机在那清除数据 编辑:程序博客网 时间:2024/06/06 17:57
1. 模式定义
要求一次性地获取多条数据并展示出来
该怎么实现,才能既把多条用户数据的姓名显示出来,而又能节省内存空间?
代理模式的定义:
为其他对象提供一种代理以控制对这个对象的访问。
代理模式引入一个Proxy对象来解决这个问题。刚开始只有用户编号和姓名的时候,不是一个完整的用户对象,而是一个代理对象。当需要访问完整的用户数据时,代理会从数据库中重新获取相应的数据。
2. UML图
Proxy:代理对象,实现与具体的目标对象一样的接口,这样可以使用代理来代替具体的目标对象。保存一个指向具体目标对象的引用,可以在需要的时候调用具体的目标对象。
Subject:目标接口,定义代理和具体目标对象的接口
RealSubject:具体的目标对象,真正实现目标接口要求的功能
代码:
/** * 描述用户数据的对象 */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"; }}/** * 定义用户数据对象的接口 */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);}/** * 代理对象,代理用户数据对象 */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"); }}/** * 实现示例要求的功能 */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"); }}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()); } }}
3. 研磨设计模式
1) 代理模式的功能:
代理模式是通过创建一个代理对象,用这个代理对象去代表实际真实的对象,客户端得到这个代理对象后,对客户端没有什么影响,就跟得到了真实对象一样来使用
2) 代理模式的本质是:控制对象访问
当客户端操作这个代理对象时,实际功能最终还是会由真实的对象完成。
3) 虚代理:根据需要创建一个开销很大的对象,该对象只有在需要的时候才被真正创建
保护代理:控制对原始对象的访问,多用于对象应该有不同的访问权限
//保护代理/** * 订单对象的接口定义 */public interface OrderApi { /** * 获取订单订购的产品名称 * @return 订单订购的产品名称 */ public String getProductName(); /** * 设置订单订购的产品名称 * @param productName 订单订购的产品名称 * @param user 操作人员 */ public void setProductName(String productName,String user); /** * 获取订单订购的数量 * @return 订单订购的数量 */ public int getOrderNum(); /** * 设置订单订购的数量 * @param orderNum 订单订购的数量 * @param user 操作人员 */ public void setOrderNum(int orderNum,String user); /** * 获取创建订单的人员 * @return 创建订单的人员 */ public String getOrderUser(); /** * 设置创建订单的人员 * @param orderUser 创建订单的人员 * @param user 操作人员 */ public void setOrderUser(String orderUser,String user);}/** * 订单对象 */public class Order implements OrderApi{ /** * 订单订购的产品名称 */ private String productName; /** * 订单订购的数量 */ private int orderNum; /** * 创建订单的人员 */ private String orderUser; /** * 构造方法,传入构建需要的数据 * @param productName 订单订购的产品名称 * @param orderNum 订单订购的数量 * @param orderUser 创建订单的人员 */ public Order(String productName,int orderNum,String orderUser){ this.productName = productName; this.orderNum = orderNum; this.orderUser = orderUser; } public String getProductName() { return productName; } public void setProductName(String productName,String user) { this.productName = productName; } public int getOrderNum() { return orderNum; } public void setOrderNum(int orderNum,String user) { this.orderNum = orderNum; } public String getOrderUser() { return orderUser; } public void setOrderUser(String orderUser,String user) { this.orderUser = orderUser; }}/** * 订单的代理对象 */public class OrderProxy implements OrderApi{ /** * 持有被代理的具体的目标对象 */ private Order order=null; /** * 构造方法,传入被代理的具体的目标对象 * @param realSubject 被代理的具体的目标对象 */ public OrderProxy(Order realSubject){ this.order = realSubject; } public void setProductName(String productName,String user) { //控制访问权限,只有创建订单的人员才能够修改 if(user!=null && user.equals(this.getOrderUser())){ order.setProductName(productName, user); }else{ System.out.println("对不起"+user+",您无权修改订单中的产品名称。"); } } public void setOrderNum(int orderNum,String user) { //控制访问权限,只有创建订单的人员才能够修改 if(user!=null && user.equals(this.getOrderUser())){ order.setOrderNum(orderNum, user); }else{ System.out.println("对不起"+user+",您无权修改订单中的订购数量。"); } } public void setOrderUser(String orderUser,String user) { //控制访问权限,只有创建订单的人员才能够修改 if(user!=null && user.equals(this.getOrderUser())){ order.setOrderUser(orderUser, user); }else{ System.out.println("对不起"+user+",您无权修改订单中的订购人。"); } } public int getOrderNum() { return this.order.getOrderNum(); } public String getOrderUser() { return this.order.getOrderUser(); } public String getProductName() { return this.order.getProductName(); } public String toString(){ return "productName="+this.getProductName()+",orderNum="+this.getOrderNum()+",orderUser="+this.getOrderUser(); }}public class Client { public static void main(String[] args) { //张三先登录系统创建了一个订单 OrderApi order = new OrderProxy(new Order("设计模式",100,"张三")); //李四想要来修改,那就会报错 order.setOrderNum(123, "李四"); //输出order System.out.println("李四修改后订单记录没有变化:"+order); //张三修改就不会有问题 order.setOrderNum(123, "张三"); //再次输出order System.out.println("张三修改后,订单记录:"+order); }}
4) Java对代理模式提供了内建的支持,在java.lang.reflect包下面,提供了一个Proxy和InvocationHandler。
静态代理和动态代理:
静态代理实现的时候,在Subject接口上定义了很多的方法,代理类里面自然也要实现很多方法
而动态代理实现的时候,虽然Subject接口上定义了很多的方法,但是动态代理类只有一个invoke方法。
/** * 使用Java中的动态代理 */public class DynamicProxy implements InvocationHandler{ /** * 被代理的对象 */ private OrderApi order = null; /** * 获取绑定好代理和具体目标对象后的目标对象的接口 * @param order 具体的订单对象,相当于具体目标对象 * @return 绑定好代理和具体目标对象后的目标对象的接口 */ public OrderApi getProxyInterface(Order order){ //设置被代理的对象,好方便invoke里面的操作 this.order = order; //把真正的订单对象和动态代理关联起来 OrderApi orderApi = (OrderApi) Proxy.newProxyInstance( order.getClass().getClassLoader(), order.getClass().getInterfaces(), this); return orderApi; } public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { //如果是调用setter方法就需要检查权限 if(method.getName().startsWith("set")){ //如果不是创建人,那就不能修改 if(order.getOrderUser()!=null && order.getOrderUser().equals(args[1])){ //可以操作 return method.invoke(order, args); }else{ System.out.println("对不起,"+args[1]+",您无权修改本订单中的数据"); } }else{ //不是调用的setter方法就继续运行 return method.invoke(order, args); } return null; }}public class Client { public static void main(String[] args) { //张三先登录系统创建了一个订单 Order order = new Order("设计模式",100,"张三"); //创建一个动态代理 DynamicProxy dynamicProxy = new DynamicProxy(); //然后把订单和动态代理关联起来 OrderApi orderApi = dynamicProxy.getProxyInterface(order); //以下就需要使用被代理过的接口来操作了 //李四想要来修改,那就会报错 orderApi.setOrderNum(123, "李四"); //输出order System.out.println("李四修改后订单记录没有变化:"+orderApi); //张三修改就不会有问题 orderApi.setOrderNum(123, "张三"); //再次输出order System.out.println("张三修改后,订单记录:"+orderApi); }}
- 代理(Proxy)模式
- 代理(Proxy)模式
- 代理(Proxy)模式
- proxy(代理)模式
- 代理模式(Proxy)
- 代理模式(Proxy)
- 代理模式(Proxy)
- Proxy(代理模式)
- 代理(proxy)模式
- 代理模式(Proxy)
- Proxy(代理)模式
- 代理模式(PROXY)
- 代理模式(Proxy)
- 代理(proxy)模式
- 代理模式(Proxy)
- 代理(Proxy)模式
- 代理模式(Proxy)
- 代理模式(Proxy)
- TreeMap类源码解析
- Hbase--1 简介
- 谁将成为中国版底特律?
- javax.jms.JMSException: Failed to build body from content. Serializable class not available to broke
- SVM-支持向量机算法概述
- 代理模式(Proxy)
- 第二次XSS测试
- [kuangbin带我飞]数位DP F(x)
- 利用jclasslib修改java编译后的.class文件
- iOS蓝牙开发(一)蓝牙相关基础知识
- chapter 1:计算机系统漫游
- 28附加题 八皇后问题
- [Database] 数据库索引-聚合索引与非聚合索引
- POJ 1789