C# 当中的 AOP 实现,函数式编程

AOP的定义就是,面向切面编程。

可以通过预编译方式和运行期动态代理实现在不修改源代码的情况下给程序动态统一添加功能的一种技术。AOP实际是GoF设计模式的延续,设计模式孜孜不倦追求的是调用者和被调用者之间的解耦,提高代码的灵活性和可扩展性,AOP可以说也是这种目标的一种实现。

它的主要功能就是将业务逻辑代码当中的公用代码提取出来,在需要的地方进行注入即可,这样能够将这些行为从逻辑代码当中分离开来,建立良好的代码体系。

举个栗子:

 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
48
49
50
51
52
53
54
55
56
57
58
59
60
public bool InsertCustomer(string firstName, string lastName, int age,   
    Dictionary<string, string> attributes)  
{  
    if (string.IsNullOrEmpty(firstName))   
        throw new ApplicationException("first name cannot be empty");  
    if (string.IsNullOrEmpty(lastName))  
        throw new ApplicationException("last name cannot be empty");  
    if (age < 0)  
        throw new ApplicationException("Age must be non-zero");  
    if (null == attributes)  
        throw new ApplicationException("Attributes must not be null");  
      
    // 日志记录
    Logger.Writer.WriteLine("Inserting customer data...");  
    DateTime start = DateTime.Now;  
      
    try  
    {  
        // 实际功能代码
        CustomerData data = new CustomerData();  
        bool result = data.Insert(firstName, lastName, age, attributes);  
        if (result == true)  
        {  
            Logger.Writer.Write("Successfully inserted customer data in "   
                + (DateTime.Now-start).TotalSeconds + " seconds");  
        }  
        return result;  
    }  
    catch (Exception x)  
    {  
        try  
        {  
            CustomerData data = new CustomerData();  
            if (result == true)  
            {  
                Logger.Writer.Write("Successfully inserted customer data in "   
                    + (DateTime.Now-start).TotalSeconds + " seconds");  
            }  
            return result;  
        }  
        catch   
        {  
            // 调用失败的时候,进行重试,并且记录到日志当中
            Exception current = x;  
            int indent = 0;  
            while (current != null)  
            {  
                string message = new string(Enumerable.Repeat('\t', indent).ToArray())  
                    + current.Message;  
                Debug.WriteLine(message);  
                Logger.Writer.WriteLine(message);  
                current = current.InnerException;  
                indent++;  
            }  
            Debug.WriteLine(x.StackTrace);  
            Logger.Writer.WriteLine(x.StackTrace);  
            return false;  
        }  
    }  
}   

其实真正工作的逻辑代码只有两行,调用了CustomerData实例的一个方法插入了一个Customer。如果有一个新的UpdateCustomer方法,你又不得不拷贝这些样板代码。 如果你使用了AOP框架的话,你就可以这样来书写你的InsertCustomer方法:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
[EnsureNonNullParameters]  
[Log]  
[TimeExecution]  
[RetryOnceOnFailure]  
public void InsertCustomerTheCoolway(string firstName, string lastName, int age,  
    Dictionary<string, string> attributes)  
{  
    CustomerData data = new CustomerData();  
    data.Insert(firstName, lastName, age, attributes);  
}  

下面我们将使用一个简单的工具类来让我们的代码变得像下面一样的简洁,而不需要使用那些庞大的第三方框架:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
public void InsertCustomerTheEasyWay(string firstName, string lastName, int age,  
    Dictionary<string, string> attributes)  
{  
    AspectF.Define  
        .Log(Logger.Writer, "Inserting customer the easy way")  
        .HowLong(Logger.Writer, "Starting customer insert",   
        "Inserted customer in {1} seconds")  
        .Retry()  
        .Do(() =>  
            {  
                CustomerData data = new CustomerData();  
                data.Insert(firstName, lastName, age, attributes);  
            });  
}  

原文 译文

Built with Hugo
主题 StackJimmy 设计