Java 设计模式 之 代理模式

Java 设计模式 之 代理模式(Proxy)  

2011-08-06 14:31:00|  分类:Java 设计模式 |  标签:代理模式  proxy  |字号 订阅

代理模式的定义:为其他对象提供一种代理以控制对象的访问。

代理模式的结构

Java 设计模式 之 代理模式(Proxy) - 低调的华丽 - 辉色空间

● Proxy :代理对象,实现与具体的目标对象一样的接口,这样就可以使用代理来代替具体的目标对象。保存一个指向具体目标对象的引用,可以在需要的时候调用具体的目标对象。可以控制对具体目标对象的访问,并可以负责创建和删除它。

● Subject :目标接口,定义代理和目标对象的接口,这样就可以在任何使用具体目标对象的地方使用代理对象。

● RealSubject :具体的目标对象,真正实现目标接口要求的功能。

代理模式是通过创建一个代理对象,用这个代理对象去代表真实的对象,客户端得到这个代理对象后,对客户端并没有什么影响,就跟得到一个真实对象一样来使用。当客户端操作这个代理对象的时候,实际上功能最终还是会由真实的对象来完成,只不过是通过代理来操作的,也就是客户端操作代理,代理操作真正的对象。正是因为有代理对象夹在客户端和被代理的真实对象中间,相当于一个中转,那么在中转的时候就可以有许多花招可以玩,比如,判断一下权限,如果没有足够的权限就不给你中转了。

代理的分类

● 虚代理:根据需要来创建开销很大的对象,该对象只有在需要的时候才真正被创建。

● 远程代理:用来在不同的地址空间上代表一个对象,这个不同的地址空间可以是本机,也可以在其他机器上。在Java里最典型的就是RMI

● copy-on-write 代理:在客户端操作的时候,只有对象却是改变了,才会真正的copy(或clone)一个对象,算是虚代理的一个分支。

● 保护代理:控制对原始对象的访问,如果需要,可以给不同的用户提供不同的访问权限,以控制他们对原始对象的访问。

● Cache 代理:为那些昂贵操作的结果提供临时的存储空间,以便多个客户可以共享这些结果。

● 防火墙代理:保护对象不被恶意用户访问和操作。

● 同步代理:使多个用户能够同时访问目标对象而没有冲突。

● 智能代理:在访问对象的时候执行一些附加操作,比如,对指向实际对象的引用计数、第一次引用一个持久对象时,将他装入内存等。

㈠ 虚代理

可以根据需要来创建“大”对象,只要到必须创建的时候,虚代理才会创建对象,从而大大加快程序运行的速度,并节省资源。通过虚代理可以对系统进行优化。

Java 设计模式 之 代理模式(Proxy) - 低调的华丽 - 辉色空间

 /**
 * 定义用户数据对象的接口
 *
 */
public interface UserModelApi {

          public String getUserId();
          public void setUserId(String userId);
          public String getName();
          public void setName(String name);
          public String getDepId();
          public voidsetDepId(String depId);
          public String getSex();
          public void setSex(String sex);
}

/**
 * 目标对象
 *
 */
public class UserModelimplements UserModelApi {

          private String userId;
          private String name;
          private String depId;
          private String sex;

        //省略setter and getter

}

/**
 * 代理对象,代理用户数据对象
 *
 */
public class Proxy implements UserModelApi {
        private final UserModeluserModel;
        /**
         * 标识是否已经重新装载过数据
         */
       private boolean loaded= false;
 
       public Proxy(UserModel userModel){
                  this.userModel= userModel;
       }
 
       private void reload(){
                  System.out.println("重新查询数据库获取完整的数据,userId=="+userModel.getUserId());
                  Connection conn = null;
                  PreparedStatement pstmt = null;
                  ResultSet rs = null;
  
                  String sql = "select * from student where userId = ?";
  
                  try{
                       conn = Database.getConnection();
                       pstmt = conn.prepareStatement(sql);
                       pstmt.setString(1, userModel.getUserId());
                       rs = pstmt.executeQuery();
                       if(rs.next()){
                              userModel.setDepId(rs.getString("depId"));
                              userModel.setSex(rs.getString("sex"));
                      }
                }catch(Exception e){
                            e.printStackTrace();
                }finally{
                            Database.close(conn, pstmt, rs);
                }
       }
 
        @Override
        public String getUserId() {
                  return userModel.getUserId();
        }

        @Override
        public void setUserId(String userId) {
                  userModel.setUserId(userId);
        }

        @Override
        public String getName() {
                  return userModel.getName();
        }

        @Override
       public void setName(String name) {
                 userModel.setName(name);
       }

       @Override
       public String getDepId() {
                 if(!this.loaded){
                        reload();
                        this.loaded= true;
                 }
                return userModel.getDepId();
      }

      @Override
       public void setDepId(String depId) {
                userModel.setDepId(depId);
       }

       @Override
       public String getSex() {
                 if(!this.loaded){
                             reload();
                             this.loaded =true;
                 }
                 return userModel.getSex();
      }

      @Override
      public void setSex(String sex) {
                userModel.setSex(sex);
       }

}

public class UserManager {

         /**
          * 根据部门编号来获取所有人
          * @param depId, 部门编号
          * @return 该部门下的所有人
          */
         public Collection<UserModelApi> getUserByDepId(String depId){
                   Collection<UserModelApi> col = newArrayList<UserModelApi>();
                   Connection conn = null;
                   PreparedStatement pstmt = null;
                   ResultSet rs = null;
                   String sql = "select userId, name from student where depId like ?";
                   try{
                          conn = Database.getConnection();
                          pstmt = conn.prepareStatement(sql);
                          pstmt.setString(1, depId + "%");
                          rs = pstmt.executeQuery();
   
                          while(rs.next()){
                                  Proxy proxy = newProxy(new UserModel());
                                  proxy.setUserId(rs.getString("userId"));
                                  proxy.setName(rs.getString("name"));
                                  col.add(proxy);
                         }
                 }catch(SQLException e){
                         e.printStackTrace();
                 }finally{
                         Database.close(conn, pstmt, rs);
                 }
                 return col;
          }
}

public class Client {

          public static void main(String[] args) {
                    UserManager manager = newUserManager();
                    Collection<UserModelApi> col = manager.getUserByDepId("0101");
                    //如果只显示用户名称,则不需要重新查询数据库
                    for(UserModelApi user : col){
                               System.out.println("用户编号:=" + user.getUserId() + ",用户姓名:=" + user.getName());
                     }
                     //如果访问非用户编号和用户名以外的属性,那就会重新查询数据库
                     for(UserModelApi user : col){
                             System.out.println("用户编号:=" + user.getUserId() + ",用户姓名:=" + user.getName() +
                                           ",所属部门:=" + user.getDepId());
                     }
          }
}

/**
 * 数据库对象,存放一些操作数据库的方法
 *
 */
public class Database {

          private static final StringDATABASE_CONFIG_FILE = "databaseConfigFile";
          private static StringDRIVER;
          private static StringURL;
          private static StringUSERNAME;
          private static StringPASSWORD;
 
          static{
                     ResourceBundle resource = ResourceBundle.getBundle(DATABASE_CONFIG_FILE);
                     DRIVER = resource.getString("DRIVER").trim();
                     URL = resource.getString("URL").trim();
                     USERNAME = resource.getString("USERNAME").trim();
                     PASSWORD = resource.getString("PASSWORD").trim();
           }

           public static Connection getConnection()throws SQLException{
                     Connection conn = null;
                     try{
                          Class.forName(DRIVER);
                          conn = DriverManager.getConnection(URL,USERNAME , PASSWORD);
                     }catch(ClassNotFoundException e){
                          e.printStackTrace();
                     }
                     return conn;
           }


          public static void closeConnection(Connection conn){
                    try{
                         if(conn !=null){
                                  conn.close();
                         }
                    }catch(SQLException e){
                         e.printStackTrace();
                    }
         }


         public static void closePreparedStatement(PreparedStatement pstmt){
                    try{
                         if(pstmt !=null){
                                 pstmt.close();
                         }
                    }catch(SQLException e){
                           e.printStackTrace();
                    }
        }


        public static void closeResultSet(ResultSet rs){
                   try{
                        if(rs !=null){
                                rs.close();
                        }
                  }catch(SQLException e){
                        e.printStackTrace();
                  }
        }


        public static void close(Connection conn, PreparedStatement pstmt, ResultSet rs){
                   closeResultSet(rs);
                   closePreparedStatement(pstmt);
                   closeConnection(conn);
        }
}

/*  数据库配置文件 */

src/databaseConfigFile.properties

DRIVER=com.microsoft.jdbc.sqlserver.SQLServerDriver
URL=jdbc:microsoft:sqlserver://localhost:1433;DatabaseName=demo
USERNAME=sa
PASSWORD=joe

从上面的实例可以看出,如果只访问用户编号和用户姓名的数据,是不需要重新查询数据库的。只有当访问到这两个数据以外的数据时,才需要重新查询数据库获得完整的数据,从而节省了内存。但这有个潜在的问题,就是当要查询全部的数据时,就会执行N+1 次数据查询。这类似Hibernate 中的 Lazy Load 的情况也存在 N + 1次查询的操作,原因就在于,Hibernate 的 Lazy Load 就是使用代理来实现的。

原文:http://joe5456536.blog.163.com/blog/static/853747732011762349570/


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值