zoukankan      html  css  js  c++  java
  • 代理模式小试

    一、介绍

    什么是代理模式。

    惯例,我们先看一下《研磨设计模式》中的介绍——为其他对象提供一种代理以控制对这个对象的访问。代理模式的本质是——控制对象访问

    什么意思呢?

    就是我们每次访问一个对象的时候,实际上去访问这个对象的代理。这个代理实际上就是这个对象的替身,可以实现原本对象绝大多数的功能。只有当需要某些特殊功能的时候,才去调用原本的对象。这样一来,在不修改原对象的情况下,就可以在代理对象上实现很多特殊的功能。这些功能基本都属于访问控制。

    这里所说的代理跟我们平时所说的各种代理,其实就是一个意思。所以说,像JDK动态代理、CGLib动态代理这些也都是代理模式的一个体现。

    关于JDK动态代理和CGLib动态代理的简单演示可以参考一下我的另一篇博文JDK动态代理和CGLib动态代理简单演示

    二、我的实现

    假设我们有一个user表,对应一个实体类User。它有一个字段是passward。现在我们需要控制这个字段的访问权限,只有它本人才能查看和修改,管理员也只能查看,不能修改。

    一般可以采用接口的设计,让代理类和被代理类都实现同一个接口,但是,这里演示为了减少耦合,就不这么做了。如下:

    1、很简单的实体类:

     1 public class User {
     2 
     3     private String userId;
     4     private String userName;
     5     private String password;
     6 
     7     public User(String userId, String userName, String password) {
     8         super();
     9         this.userId = userId;
    10         this.userName = userName;
    11         this.password = password;
    12     }
    13 
    14     public String getUserId() {
    15         return userId;
    16     }
    17 
    18     public void setUserId(String userId) {
    19         this.userId = userId;
    20     }
    21 
    22     public String getUserName() {
    23         return userName;
    24     }
    25 
    26     public void setUserName(String userName) {
    27         this.userName = userName;
    28     }
    29 
    30     public String getPassword() {
    31         return password;
    32     }
    33 
    34     public void setPassword(String password) {
    35         this.password = password;
    36     }
    37 
    38 }

    2、很简单的代理类:

     1 public class UserProxy {
     2 
     3     User user = null;
     4 
     5     UserProxy(User user) {
     6         this.user = user;
     7     }
     8 
     9     public String getUserId() {
    10         return user.getUserId();
    11     }
    12 
    13     public void setUserId(String userId) {
    14         user.setUserId(userId);
    15     }
    16 
    17     public String getUserName() {
    18         return user.getUserName();
    19     }
    20 
    21     public void setUserName(String userName) {
    22         user.setUserName(userName);
    23     }
    24 
    25     // 查看密码做权限控制
    26     public String getPassword() {
    27         // 判断是否为用户本身,或管理员
    28         if (isSelf() || isManager()) {
    29             return user.getPassword();
    30         } else {
    31             System.out.println("对不起," + user.getUserName() + ",您没有足够的权限!");
    32             return null;
    33         }
    34     }
    35 
    36     // 修改密码做权限控制
    37     public void setPassword(String password) {
    38         // 判断是否为用户本身
    39         if (isSelf()) {
    40             user.setPassword(password);
    41         } else {
    42             System.out.println("对不起," + user.getUserName() + ",您没有足够的权限!");
    43         }
    44     }
    45 
    46     // 权限判断,是否为用户自身
    47     private boolean isSelf() {
    48         // 一般可以在session中当前用户id,比较。
    49         // 这里假设不是用户自身
    50         return false;
    51     }
    52 
    53     // 权限判断,是否为管理员
    54     private boolean isManager() {
    55         // 一般可以在session中当前用户id,比较。
    56         // 这里假设是管理员
    57         return true;
    58     }
    59 }

    3、我们测试一下:

     1 public class Test {
     2 
     3     public static void main(String[] args) {
     4         User user = new User("001", "张三", "12345");
     5         UserProxy proxy = new UserProxy(user);
     6         System.out.println("用户名:" + proxy.getUserName());
     7         System.out.println("现在查看密码!");
     8         System.out.println("用户密码:" + proxy.getPassword());
     9         System.out.println("现在修改密码!");
    10         proxy.setPassword("54321");
    11     }
    12 }

    如上,实现了简单的权限控制了。

    三、虚代理

    代理有很多种,如虚代理、远程代理、copy-on-write、保护代理、Cache代理、防火墙代理、同步代理、智能代理等等。

    需要仔细了解,可以自行查找相关资料。

    不过万变不离其宗,这些代理都是符合代理模式的思想的。

    上面我的实现,演示的是保护代理。这里再简要介绍一下虚代理。

    什么是虚代理呢?对于创建开销很大的对象,用一个创建开销较小的代理对象代替,一般情况下,这个代理对象足够应付绝大多数用户请求。只有当用户请求原对象的特殊功能时,才会创建原对象。

    《研磨设计模式》介绍了一种很常用的实现:

    一个数据表有很多字段,通常只需要显示其中几个字段,这种情况下就需要使用虚代理来进行优化了。如下:

    1、这里用一个接口来统筹目标对象和代理对象,只有简单的get/set方法,如下:

     1 public interface UserModelApi {
     2 
     3     public String getUserId();
     4     
     5     public void setUserId();
     6     
     7     public String getUserName();
     8     
     9     public void setUserName();
    10     
    11     public String getPassname();
    12     
    13     public void setPassname();
    14     
    15 }

    2、目标类这里就不列出了,代理类如下:

     1 public class MyProxy implements UserModelApi {
     2 
     3     // 数据库初次查询后得到的对象,只有一部分字段。
     4     private UserModelApi object = null;
     5 
     6     // 标记是否被加载过,即是否深入查询过。
     7     private boolean loaded = false;
     8 
     9     public MyProxy(UserModelApi object) {
    10         this.object = object;
    11     }
    12 
    13     @Override
    14     public String getUserId() {
    15         return object.getUserId();
    16     }
    17 
    18     @Override
    19     public String getUserName() {
    20         return object.getUserName();
    21     }
    22 
    23     @Override
    24     public void setUserId(String userId) {
    25         object.setUserId(userId);
    26     }
    27 
    28     @Override
    29     public void setUserName(String userName) {
    30         object.setUserName(userName);
    31     }
    32 
    33     @Override
    34     public void setPassword(String password) {
    35         // 设置属性和查询不同,需要另外的
    36         object.setPassword(password);
    37     }
    38 
    39     @Override
    40     // 这里,当请求得到password的时候,由于传入的UserModelApi对象并未包含这个字段
    41     // 所以需要深入查询。
    42     public String getPassword() {
    43         // 需要判断是否已经装载过了
    44         if (!this.loaded) {
    45             reload();
    46             this.loaded = true;
    47         }
    48         return object.getPassword();
    49     }
    50 
    51     private void reload(){
    52         //查询数据库,注入字段到object对象
    53     }
    54 }

    ------------------------------------------------------------------------------------------------------------------------------------------------------------

    PS:如果本篇博文您觉得不错的话,请别忘了推荐一下,谢谢。

    /**
    *   ————————如果觉得本博文还行,别忘了推荐一下哦,谢谢!
    *   作者:钱书康
    *   欢迎转载,请保留此段声明。
    *   出处:http://www.cnblogs.com/zrtqsk/
    */
  • 相关阅读:
    使用nmon进行系统监控
    linux中内存使用原理
    测试网站访问速度的5个方法
    手机站点击商务通无轨迹解决方法
    PHP开启伪静态配置
    Phpcms V9当前栏目及所有二级栏目下内容调用标签
    手机访问网跳转到手机端
    移动端web开发技巧 -- 转载
    php错误:You don't have permission to access / on this server.
    Navicat for MySQL使用手记(上)--创建数据库和表
  • 原文地址:https://www.cnblogs.com/zrtqsk/p/3694816.html
Copyright © 2011-2022 走看看