首頁 > Java > java教程 > java設計模式之代理模式實例講解

java設計模式之代理模式實例講解

黄舟
發布: 2017-09-28 09:24:18
原創
1736 人瀏覽過

下面小編就為大家帶來一篇java設計模式-代理模式(實例講解)。小編覺得蠻不錯的,現在就分享給大家,也給大家做個參考。一起跟著小編過來看看吧

代理模式是java最常見的設計模式之一。 spring的aop就是使用了代理模式。

一般而言,代理模式分為靜態代理程式和動態代理兩種。

作為結構類別的設計模式,作用在於不修改類別內部程式碼的情況下,對類別進行拓展,是繼承機制的一種補充。

eg :以下就使用者登入這個範例實作一下代理模式。

基本需求是:實作使用者的登入和修改暱稱功能。

上程式碼,先是IUser介面與user實作類別


1

2

3

4

5

6

7

public interface IUser {

 //登录

 void login(String userId,String password);

 //修改昵称

 void editNickname(String nickname);

 

}

登入後複製


1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

public class User implements IUser {

  

 private String nickname;

 private String userId;

 private String password;

  

 public User(String userId,String password){

  this.userId = userId;

  this.password = password;

 }

 

 @Override

 public void login(String userId, String password){

  if(this.userId == userId && this.password == password){

   System.out.println("用户登录成功");

  }

  else

   System.out.println("用户登录失败");

 }

 

 @Override

 public void editNickname(String nickname) {

  this.nickname = nickname;

  System.out.println("修改昵称成功,当前用户的昵称是:"+this.nickname);

 }

 

}

登入後複製

客戶端類別


#

1

2

3

4

5

6

7

public class Client {

 public static void main(String[] args) {

  //不调用代理模式时

  IUser user = new User("firs","123");

  user.login("firs", "123");

  user.editNickname("大风");

}

登入後複製

還是很簡單的。可是後面產品經理跟你說,我們需要增加一個記錄使用者行為的功能,這下該怎麼辦呢?直接修改user類別?不不不,用代理模式。

增加一個代理類,在代理類裡面寫「記錄用戶行為」的功能就好,不修改類,只拓展類,減少錯誤發生。


1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

import java.util.Date;

import java.util.HashMap;

import java.util.Map;

 

/**

 * 静态代理类必须实现接口,而且需要新创建一个类的代码出来

 * @author Administrator

 *

 */

public class StaticProxy implements IUser {

 private IUser user;

 public StaticProxy(String userId,String password){

  this.user = new User(userId,password);

 }

  

 //登陆前的操作,记录当前登录的时间

 void noteLoginInfo(String[] params, String opreate){

  Map<String,Object> loginInfo = new HashMap<>();

  loginInfo.put("params", params);

  loginInfo.put("opreate", opreate);

  loginInfo.put("opreateTime", new Date());

  System.out.println("记录用户操作成功");

 }

  

 @Override

 public void login(String userId, String password){

   

  noteLoginInfo(new String[]{userId, password},"login");

   

  user.login(userId, password);

 }

 

 @Override

 public void editNickname(String nickname) {

  noteLoginInfo(new String[]{nickname},"editNickname");

  user.editNickname(nickname);

 }

 

}

登入後複製

客戶端類別:


#

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

public class Client {

 public static void main(String[] args) {

  //不调用代理模式时

  IUser user = new User("firs","123");

  user.login("firs", "123");

  user.editNickname("大风");

   

  System.out.println("");

  System.out.println("=============调用静态代理模式后===========");

   

  //需要实现记录用户登录和修改昵称操作的日志功能

  //基于“拓展开发,修改关闭”的设计准则,我们可以用静态代理的方式

  IUser proxy = new StaticProxy("firs","123");

  proxy.login("firs", "123");

  proxy.editNickname("我还是大风");

 

}

登入後複製

這樣子只需要修改客戶端類別和增加靜態代理程式就可以了,完美實現。可是需求是無窮無盡的,產品經理跟你說:「我們增加了一個管理員角色,還有二級管理員」啥啥啥的一大堆角色,

這就尷尬了,每個角色都要建一個靜態代理類,類爆炸了吧。不急,我們有動態代理模式。

動態代理模式在於不用自己新建代理類,你傳具體的實作類別(主體)給他,他就預設為你產生了一個代理類別。

從本質上來說,它是利用了java的反射機制在運行時動態地產生了對應的代理類別。

沒有反射,就沒有動態代理。


1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

import java.lang.reflect.InvocationHandler;

import java.lang.reflect.Method;

import java.util.Date;

import java.util.HashMap;

import java.util.Map;

 

/**

 * 动态代理类不用和主体类继承同一个接口

 * @author Administrator

 *

 */

public class DynamicProxy implements InvocationHandler {

 private Object object;

 public DynamicProxy(String userId,String password,Class<?> c){

  Object obj = null;

  try {

   obj = Class.forName(c.getName())

     .getConstructor(String.class,String.class)

     .newInstance(userId,password);

  } catch (Exception e) {

   // TODO Auto-generated catch block

   e.printStackTrace();

  }

  this.object = obj;

 }

  

 //登陆前的操作,记录当前登录的时间

 void noteLoginInfo(String[] params, String opreate){

  Map<String,Object> loginInfo = new HashMap<>();

  loginInfo.put("params", params);

  loginInfo.put("opreate", opreate);

  loginInfo.put("opreateTime", new Date());

  System.out.println("记录用户操作成功");

 }

 

 @Override

 public Object invoke(Object proxy, Method method, Object[] args)

   throws Throwable {

  String[] params = new String[args.length];

  for(int i = 0 ;i < args.length ; i++){

   params[i] = args[i].toString();

  }

  noteLoginInfo(params, method.getName());

  return method.invoke(object, args);

 }

 

}

登入後複製

最後的客戶端類別:


#

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

package com.test.my;

 

import java.lang.reflect.Proxy;

 

 

public class Client {

 public static void main(String[] args) {

  //不调用代理模式时

  IUser user = new User("firs","123");

  user.login("firs", "123");

  user.editNickname("大风");

   

  System.out.println("");

  System.out.println("=============调用静态代理模式后===========");

   

  //需要实现记录用户登录和修改昵称操作的日志功能

  //基于“拓展开发,修改关闭”的设计准则,我们可以用静态代理的方式

  IUser proxy = new StaticProxy("firs","123");

  proxy.login("firs", "123");

  proxy.editNickname("我还是大风");

   

  System.out.println("");

  System.out.println("=============调用动态代理模式后===========");

   

  DynamicProxy dynamicProxy = new DynamicProxy("firs","123",Admin.class);

   

  ClassLoader cl = Admin.class.getClassLoader();

  IUser iuser = (IUser)Proxy.newProxyInstance(cl,

        new Class[]{IUser.class}, dynamicProxy);

  iuser.login("firs","123");

  iuser.editNickname("使用动态代理后的大风");

   

 }

 

}

登入後複製

因為需求而增加的Admin類別


1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

public class Admin implements IUser {

  

 private String nickname;

 private String userId;

 private String password;

  

 public Admin(String userId,String password){

  this.userId = userId;

  this.password = password;

 }

 

 @Override

 public void login(String userId, String password){

  if(this.userId == userId && this.password == password){

   System.out.println("用户登录成功");

  }

  else

   System.out.println("用户登录失败");

 }

 

 @Override

 public void editNickname(String nickname) {

  this.nickname = nickname;

  System.out.println("修改昵称成功,当前用户的昵称是:"+this.nickname);

 }

 

}

登入後複製

總結:

#1.靜態代理模式相對來說比較簡單,重點在於對於每個實作類別( subject主體)新建一個代理類,該代理類內有實體類(subject主體)的引用,因此可實現對原有實現類別(subject主體)的控制,包括aop的控制等。

2.靜態代理是有限制的,對於每個實體類可能都需要新建一個靜態代理類,這樣子可能會造成靜態代理類過多的情況,所以動態代理應運而生了。

3.動態代理不限於具體的實現類別(subject主體),在其內部是用object訪問實體類別的引用,再利用反射獲得該實體類別的各種方法,從而實現對實作類別(subject主體)的面向切面AOP編程控制。

4.上述的寫法是JDK裡的動態代理,不是特別完美,因為這種動態代理需要實體類別實現至少一個介面。問題是並不是所有的類別都會有接口,所以說不完美在這裡。

以上是java設計模式之代理模式實例講解的詳細內容。更多資訊請關注PHP中文網其他相關文章!

相關標籤:
本網站聲明
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn
最新問題
java可以做為web的後端嗎?
來自於 1970-01-01 08:00:00
0
0
0
安裝JAVA
來自於 1970-01-01 08:00:00
0
0
0
無法安裝java
來自於 1970-01-01 08:00:00
0
0
0
求救:JAVA加密的資料PHP解密
來自於 1970-01-01 08:00:00
0
0
0
熱門教學
更多>
最新下載
更多>
網站特效
網站源碼
網站素材
前端模板