Java实现泛型委托类似C#Action<T>

本文介绍了C#中的泛型委托Action<T>及其在异常处理中的应用,包括如何使用Action<T>重构重复的异常处理代码,减少冗余并提高代码可读性。同时,通过对比C#与Java在实现委托方面的差异,展示了Java如何通过接口和内部类实现类似功能。最后,提供了C#项目中使用Action<T>重构异常处理代码的具体示例。
摘要由CSDN通过智能技术生成

一、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());
	}
}


 

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值