Java實現泛型委託類似C#Action

一、C# Action<T> 泛型委託(幫助理解委託)

描述:

封裝一個方法,該方法只採用一個參數並且不返回值.

語法:

public delegate void Action<T>(T arg);

T:

參數類型:此委託封裝的方法的參數類型

arg:

參數:此委託封裝的方法的參數

備註:

通過此委託,可以將方法當做參數進行傳遞.Action<T> 泛型委託:封裝一個方法,該方法只採用一個參數並且不返回值。可以使用此委託以參數形式傳遞方法,而不用顯式聲明自定義的委託。該方法必須與此委託定義的方法簽名相對應。也就是說,封裝的方法必須具有一個通過值傳遞給它的參數,並且不能返回值。當然泛型委託不只是只能支持一個參數,它最多可以支持四個參數。 

例子:

在使用 Action<T> 委託時,不必顯式定義一個封裝只有一個參數的方法的委託。以下代碼顯式聲明瞭一個名爲 DisplayMessage 的委託,並將對 WriteLine 方法或 ShowWindowsMessage 方法的引用分配給其委託實例。 

using System;
using System.Windows.Forms;
delegate void DisplayMessage(string message);
public class TestCustomDelegate
{
public static void Main()
{
DisplayMessage messageTarget; 
if (Environment.GetCommandLineArgs().Length > 1)
messageTarget = ShowWindowsMessage;
else
messageTarget = Console.WriteLine;
messageTarget("Hello, World!"); 
} 
private static void ShowWindowsMessage(string message)
{
MessageBox.Show(message); 
}
}

以下簡化了此代碼,它所用的方法是實例化 Action<T> 委託,而不是顯式定義一個新委託並將命名方法分配給該委託。

using System;
using System.Windows.Forms;
public class TestAction1
{
public static void Main()
{
Action<string> messageTarget; 
if (Environment.GetCommandLineArgs().Length > 1)
messageTarget = ShowWindowsMessage;
else
messageTarget = Console.WriteLine;
messageTarget("Hello, World!"); 
} 
private static void ShowWindowsMessage(string message)
{
MessageBox.Show(message); 
}
}

 

下面使用 Action<T> 委託來打印 List<T> 對象的內容。 使用 Print 方法將列表的內容顯示到控制檯上。 此外還使用匿名方法將內容顯示到控制檯上。 請注意該示例不顯式聲明 Action<T> 變量。 相反,它傳遞方法的引用,該方法採用單個參數而且不將值返回至 List<T>.ForEach 方法,其單個參數是一個 Action<T> 委託。 同樣,在 C# 示例 中,Action<T> 委託不被顯式地實例化,因爲匿名方法的簽名匹配 List<T>.ForEach 方法所期望的 Action<T> 委託的簽名。 

using System;
using System.Collections.Generic;
class Program
{
static void Main()
{
List<String> names = new List<String>();
names.Add("Bruce");
names.Add("Alfred");
names.Add("Tim");
names.Add("Richard");
// Display the contents of the list using the Print method.
names.ForEach(Print);
// The following demonstrates the anonymous method feature of C#
// to display the contents of the list to the console.
names.ForEach(delegate(String name)
{
Console.WriteLine(name);
});
}
private static void Print(string s)
{
Console.WriteLine(s);
}
}

二、總結:

 

定義:委託就是可以自定義方法的執行時間。

要點:

     1. 定義方法。

     2. 聲明對象。

     3. 給對象賦值(也就是執行方法)。

 

三、Java 實現委託

 

Java是不可能實現委託的, 因爲壓根就沒有這個機制, Java中要實現委託的類似功能只能用接口/內部類, 隨便看一個AWT / Swing的程序就知了 。

 

1. 內部類實現委託   

<span style="color:#000000;">public class  實現委託{
   public static void main(String[] args){   
       //聲明對象
	    實現委託 test = new 實現委託();
	    委託 t =test. new 委託();
       
       //對象賦值 執行方法
       t.T();
   }
   
   //定義委託
   class 委託{
      public void T(){
         System.out.println("測試委託");
      }
   }
}</span>

2. 接口實現委託

<span style="color:#000000;">public interface 委託 {
	public void T();
}
public class 實現委託  implements 委託{
    public static void main(String[] args){
    	實現委託 test = new 實現委託();
        test.T();
    }
    
    public void T(){
       System.out.println("測試委託");
    }
}</span>

四、泛型委託在項目中的應用

1. C#泛型委託在項目中的應用參考網址:http://www.cnblogs.com/ASPNET2008/archive/2010/04/05/1704405.html

2. C#項目實例

   問題:我想大家在做異常時,都會利用try catch來捕獲異常,日誌就在catch塊中完成,但每個方法都寫一堆的try catch往往顯的有點彆扭。雖然寫程序時提倡儘量去捕獲具體的錯誤異常,但總會有你預想不到的異常拋出,爲此直接捕獲Exception算是不錯的做法。

   具體場景:在客戶端調用WCF服務時,我們都需要在客戶做異常處理,最常見的錯誤異常爲CommunicationException,TimeoutException,Exception示例如下:

try
            {
                //執行方法調用 
                ......
                (proxy as ICommunicationObject).Close();
            }
            catch (CommunicationException ex)
            {
                (proxy as ICommunicationObject).Abort();

                WebLog.SquareLog.CommonLogger.Error("取積分廣場首頁酒店數據異常CommunicationException:" + ex.ToString());
            }
            catch (TimeoutException ex)
            {
                (proxy as ICommunicationObject).Abort();
                WebLog.SquareLog.CommonLogger.Error("取積分廣場首頁酒店數據超時TimeoutException:" + ex.ToString());
            }
            catch (Exception ex)
            {      
                (proxy as ICommunicationObject).Close();      
                WebLog.SquareLog.CommonLogger.Error("取積分廣場首頁酒店數據異常Exception:" + ex.ToString());
            }


 

但如果這種代碼遍佈整個項目,我想就有重構的必要了,因爲項目中最好不要出現類似複製的代碼出現,爲此我們可以採用Invoke形式來重構我們已有代碼,下面給出兩個方法,一個是沒有返回值的,一個是有值的。

 

使用Action<T>後代碼如下:

public static void Invoke<TContract>(TContract proxy, Action<TContract> action)
        {
            try
            {
                action(proxy);
                (proxy as ICommunicationObject).Close();
            }
            catch (CommunicationException ex)
            {
                (proxy as ICommunicationObject).Abort();
                WebLog.SquareLog.CommonLogger.Error("取積分廣場首頁酒店數據異常CommunicationException:" + ex.ToString());
            }
            catch (TimeoutException ex)
            {
                (proxy as ICommunicationObject).Abort();
                WebLog.SquareLog.CommonLogger.Error("取積分廣場首頁酒店數據超時TimeoutException:" + ex.ToString());
            }
            catch (Exception ex)
            {        
                (proxy as ICommunicationObject).Close();      
                WebLog.SquareLog.CommonLogger.Error("取積分廣場首頁酒店數據異常Exception:" + ex.ToString());
            }
        }
        public static TReturn Invoke<TContract, TReturn>(TContract proxy, Func<TContract, TReturn> func)
        {
            TReturn returnValue = default(TReturn);
            try
            {
                returnValue = func(proxy);
            }
            catch (CommunicationException ex)
            {
                (proxy as ICommunicationObject).Abort();

                WebLog.SquareLog.CommonLogger.Error("取積分廣場首頁酒店數據異常CommunicationException:" + ex.ToString());
            }
            catch (TimeoutException ex)
            {
                (proxy as ICommunicationObject).Abort();

                WebLog.SquareLog.CommonLogger.Error("取積分廣場首頁酒店數據超時TimeoutException:" + ex.ToString());
            }
            catch (Exception ex)
            {
                WebLog.SquareLog.CommonLogger.Error("取積分廣場首頁酒店數據異常Exception:" + ex.ToString());
            }
            return returnValue;
        }


 

如何調用:可以看出客戶端代碼已經變成一條簡潔代碼了,它即完成了完整的異常處理,而且也把所有能夠捕獲的異常信息記錄下來。

調用代碼:

list = ErrorHandler.Invoke<ISearchHotelForSquare, List<HotelGenericInfo>>(cli, proxy => proxy.GetHotelGenericListForSquare(requestInfo).ToList());

3. 總結

自己理解:委託用在當很多代碼大部分代碼相同,部分代碼不同且不同的代碼在整體代碼中的位置相同的時候,可以將整體的部分封裝成一個方法(方法名如:all),然後將不同的部分的代碼寫成一個沒有返回值的方法(方法名如:part),然後使用Action<T>,將part方法像參數一樣傳遞給all函數。這樣實現代碼的重構。

上面是在C#中用Action<T>實現的。

Java中沒有Action<T>,還不能實現泛型委託,只能使用接口和內部類來實現。

下面是Java實現和Action<T>一樣功能的例子.

例子如下:

(1)公用方法

  

public class AllClass {
	public static void all(String s,Common common){
	       //此處可以寫公用的代碼
	       common.print(s);
	       //此處可以寫公用的代碼
	   }
}


 

(2)不同代碼要實現的接口

   

public interface Common {
	public void print(String s);
   }


(3)實現接口的第一個類

  

public class A implements Common{
	public void print(String s){
		System.out.print(s+="A");
	}
	
	public static void main(String[] args) {
		String s = "test";
	    AllClass.all(s,new A());
	}
}


(4)實現接口的第二個類

   

public class A implements Common{
	public void print(String s){
		System.out.print(s+="A");
	}
	
	public static void main(String[] args) {
		String s = "test";
	    AllClass.all(s,new A());
	}
}


 

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章