1. 程式人生 > >Proxy代理模式之應用

Proxy代理模式之應用

一,定義:代理模式(Proxy:為其他物件提供一種代理以控制對這個物件的訪問。

二,其類圖:

三,分類一:靜態代理

                 1,介紹:也就是需要我們為目標物件編寫一個代理物件,在編譯期就生成了這個代理物件,然後通過訪問這個代理,來實現目標物件某些功能。

                 2,簡單應用:在這裡我們看一個簡單的登入登出的例子:

登入功能的介面:

		/**
		 * 公共介面,目標物件和代理都來實現
		 */
		public interface ILogin{
		        //登入
			void login();
			//登出
			void logout();
		}

     實現的目標介面:
		/**
		 * 目標物件,實現公共介面,達到登入登出的功能
		 */
		public class Reallogin implements ILogin{
			
			public void login(){
				try {
					Thread.sleep(3200);
				} catch (InterruptedException e) {
					e.printStackTrace();
				}
				System.out.println("登入系統.....");
			}
			
			public void logout(){
				try {
					Thread.sleep(2200);
				} catch (InterruptedException e) {
					e.printStackTrace();
				}
				System.out.println("退出系統....");
			}
		}

大家看見了,上邊的方法中我們加入了執行緒的睡眠,因為我想通過代理模式來測試登入登出的時間,因為JAVA程式我們遵循OCP(對擴充套件開放,對修改關閉)原則,所以為了不修改原來程式碼,我們來採用靜態代理模式:

        Proxy(代理物件)的程式碼:

		/**
		 * 代理物件,代理目標物件Reallogin 
		 */
		public class ProxyLogin implements ILogin{
		
		         //此類中包含了目標物件
			private Reallogin target;
			
			//構造方法
			public ProxyLogin (Reallogin target){
				this.target = target;
			}
			
			@Override
			public void login() {
			         //開始時間
				long begin = System.currentTimeMillis();
				target.login();
				//結束時間
				long end = System.currentTimeMillis();
				System.out.println("耗費時長"+(end-begin)+"毫秒");
			}
		
			@Override
			public void logout() {
				long begin = System.currentTimeMillis();
				target.logout();
				long end = System.currentTimeMillis();
				System.out.println("耗費時長"+(end-begin)+"毫秒");
			}
		
		}

好,通過代理模式,非常簡單的實現了對登入登出時間的捕獲,但是,假如客戶突然要求我們對所有的類方法的時間進行捕獲,那該怎麼辦呢?總不能每一個類,都寫一個代理類,那樣太麻煩了吧!怎麼呢???

             3,分析:通過這裡例子以及擴充套件我們來看一下靜態代理模式的缺點吧:

                     a,如果出現上邊的需求,那麼勢必會出現類爆炸的結果;

                     b,當然捕捉方法執行時間的程式碼都一樣,我們每個方法都寫,每個類都寫,這也是程式碼的重複,沒有達到程式碼複用的效果,這也完全違背了面向物件設計的原則。

            4,思考:防止出現類爆炸,使程式碼能夠得到複用。我們能不能用一個代理類,來代理所有需要計算方法執行時間呢???看下邊的動態代理模式。

四,動態代理

             1,介紹:通過反射機制,利用JDK提供的Proxy類,在程式執行的時候在記憶體中根據目標物件來建立代理物件,避免了類爆炸的出現。代理方法只寫一此,使程式碼得到了複用。

             2,解決上邊的問題:

                   a,代理方法的編寫:

		/**
		 * 此類需要實現InvocationHandler介面
		 * 呼叫處理器,當代理物件呼叫代理方法的時候,註冊在呼叫處理器中的invoke方法會自動呼叫。
		 */
		public class TimerInvocationHandler implements InvocationHandler {
		    
			//目標物件,通過反射機制獲得
			private Object target;
			//構造方法
			public TimerInvocationHandler(Object target){
				this.target = target;
			}
			
			/**
			 *  引數:
			 *  		Object proxy:代理物件的引用,proxy變數中儲存代理物件的記憶體地址(這個引數很少用)
			 *  		Method method:目標物件的目標方法。
			 *  		Object[] args:目標物件的目標方法執行的時候所需要實參。
			 */
			@Override
			public Object invoke(Object proxy, Method method, Object[] args)throws Throwable {
				//開始時間
				long begin = System.currentTimeMillis();
		
				//執行目標物件中的方法
				Object retValue = method.invoke(target, args);
				//結束時間
				long end = System.currentTimeMillis();
				//計算時間
				System.out.println("耗費時長"+(end-begin)+"毫秒");
				return retValue;
			}
		
		}

b,注意這裡的測試程式的編寫:
		/**
		 * 注意:JDK內建的動態代理Proxy只能代理介面
		 *(如果既想代理介面又想代理抽象類需要使用第三方元件:例如cglib)
		 */
		public class Test {
		
			public static void main(String[] args) {
				
				//建立目標物件
				ILogin target = new ProxyLogin();
				
				//建立代理物件:通過JDK內建的動態代理類java.lang.reflect.Proxy完成代理物件的動態建立
				//引數:
                                        ClassLoader loader;
		  			這裡的類裝載器主要是用來裝載在記憶體中生成的那個臨時的位元組碼,
		  			代理類的類裝載器需要和目標類的類裝載器一致。
		  
		  		Class[] interfaces;
		  			代理類和目標類必須實現“同一些”介面。(一個類可以同時實現多個介面)
		  
		  		InvocationHandler handler;
		  			當代理物件呼叫代理方法的時候,“註冊”在呼叫處理器中的invoke方法會自動呼叫。
				ILogin proxy = (IUserService)Proxy.newProxyInstance(target.getClass().getClassLoader(),new Class[]{IUserService.class},new TimerInvocationHandler(target)); 
				
				//通過執行代理物件的代理方法去執行目標物件的目標方法
				proxy.login();
				proxy.logout();
			}
			
		
		}

          3,動態代理模式相對來說比較難了解,因為它運用了反射機制。但是想象現實生活中,還是挺容易理解的,例如,工作中介,相當於代理模式中的代理物件,它可以為不同人找不同的工作,我們可以沒有見過咱們生活中每個人都有一個工作中介代理物件吧。所以這裡可以理解為功能代理物件,即為所有類代理可以實現同一種功能,例如上邊的捕捉時間。

五,動態模式解決Service層的JDBC程式碼,以及一些重複的程式碼:

大家都直到Service層是用來寫業務程式碼的,但是當出現事物時,我們需要在業務層進行事物的開啟,提交,回滾,結束,這樣就有了JDBC程式碼了,而且都是重複的,怎麼辦呢,我們可以為這些利用事物的業務層利用代理模式來解決這個問題。

看一下這個service層中的方法,裡邊有JDBC程式碼,而且每個Servlet都需要寫,非常不滿足規範:

			public boolean saveEnterprise(Enterprise en, List<EnInv> eninvs) throws Exception {
				Connection conn =null;
				int count=0 ;
				try {
		                                  //獲取資料連線物件
					conn=DBUtil.getConnection();
					//事物的開始
					DBUtil.beginTransaction(conn);
					count=ienterpriserDao.InsertEnterpriseDao(en, eninvs);
					         //事物的提交
					DBUtil.commitTransaction(conn);
				} catch (Exception e) {
					try {
		                                              //事物的回滾
						DBUtil.rollbackTransaction(conn);
					} catch (SQLException e1) {
						e1.printStackTrace();
					}
					e.printStackTrace();
				}finally{
					try {
		                                             //事物的結束
						DBUtil.endTransaction(conn);
					} catch (SQLException e) {
						e.printStackTrace();
				}
					DBUtil.close(conn, null, null);
				}
				return count==(1+eninvs.size());

}

通過Prox動態代理:

代理方法的編寫:

		public class TransactionInvcationHandler implements InvocationHandler {
			//目標物件的建立
			private Object target;
			
			//編寫構造方法,
			public TransactionInvcationHandler(Object target){
				this.target=target;
			}
			@Override
			/**
			 * 利用事物的操作的呼叫事物處理
			 */
			public Object invoke(Object proxy, Method method, Object[] args)
					throws Throwable {
				
				Object retValue=null;
				Connection conn=null;
				try{
					conn=DBUtil.getConnection();
					//開啟事物
					DBUtil.beginTransaction(conn);
					
					//執行目標物件的方法
					retValue=method.invoke(target, args);
					
					//提交事物
					DBUtil.commitTransaction(conn);
				}catch(Exception e ){
					
					//回滾事物
					DBUtil.rollbackTransaction(conn);
					e.printStackTrace();
				}finally{
					//關閉事物
					DBUtil.endTransaction(conn);
					DBUtil.close(conn, null, null);
				}
				
				
				return retValue;
			}
		
		}

這樣這個Service就只需要寫這兩句話了:
		public boolean saveEnterprise(Enterprise en, List<EnInv> eninvs) throws Exception {
			int count=0 ;
				count=ienterpriserDao.InsertEnterpriseDao(en, eninvs);
			return count==(1+eninvs.size());

}

當然Servlet的呼叫和上邊的那個測試程式一樣,我就不再寫了。總而言之,動態代理模式模仿我們生活中的中介代理,使我們的程式程式碼達到了非常好的複用和分類清楚,非常實用。

代理模式的其他應用:

              1,遠端代理,為一個物件在不同的地址空間提供區域性代表。這樣可以隱藏一個物件存在於不同地址空間的事實。

              2,虛擬代理,根據需要建立開銷很大的物件。通過它來存放例項化需要很長時間的真實物件。例如,網頁中在圖片出來以前現出來文字。

              3,安全代理,用來控制真實物件訪問時的許可權。

              4,智慧代理,是指當呼叫真實的物件時,代理處理另外一些事。

總而言之,這次的學習,有感覺軟體和我們生活是息息相關的,善於發現生活的點點滴滴,從軟體中聯想生活會理解的更深,學習的更好!!!!


相關推薦

Proxy代理模式應用

一,定義:代理模式(Proxy):為其他物件提供一種代理以控制對這個物件的訪問。 二,其類圖: 三,分類一:靜態代理                  1,介紹:也就是需要我們為目標物件編寫一個代理物件,在編譯期就生成了這個代理物件,然後通過訪問這個代理,來實現目

Java設計模式(八)Proxy代理模式

com 服務器 exp 技術分享 如果 face pub [] his 一、場景描述 代理在生活中並不少見,租房子需要找中介,打官司需要找律師,很多事情我們需要找專業人士代理我們做,另一方面,中介和律師也代理了房東、法律程序與我們打交道。 當然,設計模式中的代理與廣義的

設計模式——proxy代理模式

關系 org 類對象 設置 驗證 protect java實現 否則 總結 [toc] 概述 定義 代理模式顧名思義,作為某對象的代表,去做某些事情。例如海淘、轉運公司,代收快遞等,都是生活中的代理模式。 代理模式的英文叫做Proxy或Surrogate。 定義:代理(P

代理模式靜態代理

system rri host after int 授權 @param () 說明 package edu.aeon.proxy; /** * 說明:靜態代理 角色:真實角色、代理角色 條件:兩種覺得必須實現同一接口 例子:1.北京找房(中介) 2.結婚(找婚慶公司)

Java設計模式代理模式遠端代理

遠端代理 遠端代理是一種常用的代理模式,它使得客戶端程式可以訪問在遠端主機上的物件。為一個位於不同地址空間的物件提供一個本地的代理物件,因此,在客戶端完全可以認為被代理的遠端業務物件是在本地而不是遠端。下圖為遠端代理示意圖 Java語言中可以通過一種名為RMI(Remote Met

Java 設計---Proxy 代理模式

何謂代理模式        代理模式是指客戶端不直接呼叫服務物件,而是通過代理服務去呼叫物件。 應用場景          1.當需要為一個物件在不同的地址空間提供區域性的代表時;此時的代理模式

代理模式Cglib代理

Cglib代理,也叫做子類代理。在記憶體中構建一個子類物件從而實現對目標物件功能的擴充套件。 l  JDK的動態代理有一個限制,就是使用動態代理的物件必須實現一個或多個介面。如果想代理沒有實現介面的類,就可以使用CGLIB實現。 l    CGLIB是一個強大的高

代理模式靜態代理模式

特點: 兩個子類共同實現一個介面,其中一個子類負責真實的業務實現,另外一個子類完成輔助真實業務主題的操作。 interface ISubject { public void buyLipstick();// 核心功能是買口紅 } class RelSubject imple

設計模式學習代理模式靜態代理

設計模式學習之代理模式之靜態代理 前言 程式碼 執行結果 前言 最近發現設計模式都忘記的七七八八了,打算一邊寫一下部落格,一邊溫習一下設計模式,這裡因為最近寫了一下框架,模擬一下mybatis的代理方式 程式碼

C++設計模式-Proxy代理模式

Proxy代理模式 作用:為其他物件提供一種代理以控制對這個物件的訪問。 代理的種類: 如果按照使用目的來劃分,代理有以下幾種: 遠端(Remote)代理:為一個位於不同的地址空間的物件提供一個局域代表物件。這個不同的地址空間可以是在本機器中,也可是在另一臺機器中。遠端代理又叫做大使(Ambassador)。

Java代理模式動態代理

    代理模式是設計模式中非常重要的一種型別。代理模式從型別上來說,可以分為靜態代理和動態代理兩種型別。     假設一個場景,有一個蛋糕店,賣的蛋糕都是用蛋糕機做的,而且不同種類的蛋糕由不同的蛋糕機來做,有水果蛋糕機,巧克力蛋糕機等。它們賣的麵包片也是麵包機做的,不同種

代理模式JDK的動態代理

      JDK的動態代理比較簡單,是內建在JDK中的,不需要引入第三方jar包,但相對其他代理它的功能就比較弱了。       下面就以demo為例來學習它。分為延遲載入demo和安全作用的demo    

GOF23設計模式動態代理模式理解

 動態代理(dynamic Proxy) 動態代理(動態生成代理類) JDK自帶的動態代理 Javaassist位元組碼操作庫實現 CGLIB ASM(底層使用指令,可維護性較差

常用設計模式應用場景/好處在哪兒

3、工廠方法(把變和不變的地方隔離出來)    緊耦合和鬆耦合:如何進行模組劃分?  主模組(抽象部分)-->次模組(細節具體部分) 對模組進行分析(高層模組-->低層模組)  在軟體系統中,經常面臨著“某個物件”的建立工作;由於需求的變化,這個物件的具體實現經常面臨著劇烈的變化,但是它卻擁有比

Java代理模式應用(三)Cglib實現

前一節所說的靜態代理和動態代理模式都是要求目標物件是實現一個介面的目標物件,但是有時候目標物件只是一個單獨的物件,並沒有實現任何的介面,這個時候就可以使用以目標物件子類的方式類實現代理,這種方法就叫做:Cglib代理 1.Cglib說明 Cglib代理,

Proxy(代理)模式

  代理模式是結構型的設計模式之一(所謂結構型設計模式指的是類和類之間組合形成更大的結構),它可以為其它被代理物件提供一種代理以控制對被代理物件的訪問。代理物件和被代理的物件具有相同的介面(它們繼承自同

Java設計模式-代理模式動態代理(附原始碼分析)

具體有如下四步驟: 通過實現 InvocationHandler 介面建立自己的呼叫處理器;通過為 Proxy 類指定 ClassLoader 物件和一組 interface 來建立動態代理類;通過反射機制獲得動態代理類的建構函式,其唯一引數型別是呼叫處理器介面型別;通過建構函式建立動態代理類例項,構造時

Java代理模式及其應用

摘要:   代理根據代理類的產生方式和時機分為靜態代理和動態代理兩種。代理類不僅可以有效的將具體的實現與呼叫方進行解耦,通過面向介面進行編碼完全將具體的實現隱藏在內部,而且還可以在符合開閉原則的前提下,對目標類進行進一步的增強。典型地,Spring AOP 是

優雅的表單驗證模式--策略設計模式和ES6的Proxy代理模式

轉載自 作者 @jawil 原文,原文有刪改 網站的互動,離不開表單的提交,而一個健壯的表單離不開對錶單內容的校驗。 假設我們正在編寫一個註冊的頁面,在點選註冊按鈕之前,有如下幾條校驗邏輯。 所有選項不能為空 使用者名稱長度不能少於6位

學習C++設計新思維(泛型程式設計與設計模式應用).pdf繼承關係檢查

ok!主題是:檢查型別A與B是不是有繼承關係,在本書的P38,下面直接上程式碼。 #pragma once template<class T, class U> class Conversion { typedef char Small; class B