代理模式小试

一、介绍

什么是代理模式。

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

什么意思呢?

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

这里所说的代理跟我们平时所说的各种代理,其实就是一个意思。所以说,像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:如果本篇博文您觉得不错的话,请别忘了推荐一下,谢谢。

 

你可能感兴趣的:(代理模式)