zoukankan      html  css  js  c++  java
  • AspectF,一个.NET下超简单的轻量级AOP框架

    概要介绍

        笔者认为AspectF是比较不错的.NET下AOP解决方案,当然Spring.NET框架下的AOP功能也很强大非常出色,但这个框架相对来说比较复杂,本篇文章将着重向大家介绍AspectF这个专注于AOP的轻量级的框架的使用。AspectF可以使用一种简单的方式为你的代码添加方面(Aspects),通过使用AspectF,代码将变得干净整洁。你可以在这里获得Aspect框架相关的支持。

        如果你熟悉面向方面编程(Aspect Oriented Programming),那么你就应该知道AOP能使得代码的编写更干净清晰,可维护性更高。但AOP在.NET中的实现通常是由第三方框架(Spring.NET)或者硬编码实现,例如通过对IL的操作实现,尽管相比好处大于它带来的复杂性,但是这并不是一个简单的实现AOP的解决方案。下面我们先强调以下AOP的概念。

    Aspect Oriented Programming(AOP)

        方面(Aspects)是你在编写代码的过程中,出现在代码不同部分里的相同的程序功能片段,例如它可能是一种处理异常的方法,也可以是调用方法时的日志(logging)记录,或者是方法执行时间的记录(timming execution),这些部分很可能出现在程序的不同地方,是一些可以重用的方面。如果你在编码的过程中没有使用任何的AOP框架的话,那么你将重复的编写这些相同的代码,这使得你的代码难以维护。例如你的业务逻辑层需要进行日志记录,错误处理,执行时间需要记录,那么你的代码很可能是这样:

    public bool InsertCustomer(string firstName, string lastName, int age)
    {
        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)
        {
            Debug.WriteLine(x.StackTrace);
            Logger.Writer.WriteLine(x.StackTrace);
            return false;
        }
    }
        上面我们写了一些实际的代码,这个代码片段实现了客户信息的插入操作,同时代码中还有日志记录、异常处理和时间记录的操作,由于这种代码的混合,逻辑上显得很混乱可读性变得很差。但是设想一下,如果要在业务逻辑中添加验证或其它方面的时候,那么随着代码的添加业务逻辑将变得更乱,真是要多乱有多乱。而且当你给程序业务逻辑添加新的方法时,你需要不断的复制粘贴代码,修改这每个业务逻辑层的部分,例如:你需要在业务逻辑中添加一个UpdateCustomer的方法,你就必须在复制粘贴代码一遍,这真是很苦闷的一件事。

        再想象一下,对于修改来说,如果我们的项目需要大范围的修改错误处理的方式,那你就必须把所有业务层的方法一个一个的进行修改。然后如果新的需求又来了,要修改时间统计的方式…这过程真是苦不堪言啊。

        面向方面编程解决了上述问题,如下边代码所示,看起来是不是很简洁呢?

    [Log]
    [TimeExecution]
    public void InsertCustomerTheCoolway(string firstName, string lastName, int age)
    {
        CustomerData data = new CustomerData();
        data.Insert(firstName, lastName, age, attributes);
    }
        在AOP中你将把例如logging,timming,Validation这些方面从业务代码中进行分离。如上例所示,你可以通过Attribute解决,这样的代码干净又清晰,这里每一个Attribute代表一个方面。例如:通过添加Logging方面你可以进行日志记录。总之,无论你用了什么AOP框架,它都保证了方面在运行时被编入了你的代码中。

    简单的AOP框架AspectF

        让我们来了学习一下怎么在.NET环境下利用AspectF这个框架建立C#程序,这个程序将不使用Attribute或者IL操作实现AOP,只用简单地调用类和委托就可以了,而且使用这种方式的程序具备了很高的重用性和可维护性,而最重要的是它很轻量级,只是一个简单的类——AspectF。如下面代码所示,这是AspectF之于上例的应用:

        public void InsertCustomerTheEasyWay(string firstName, string lastName, int age)

        {

             AspectF.Define

                    .Log(Logger.Writer, "Inserting customer the easy way")

                    .HowLong(Logger.Writer, "Starting customer insert", "Inserted customer in {1} seconds")

                    .Do(() =>

                            {

                                    CustomerData data = new CustomerData();

                                    data.Insert(firstName, lastName, age);

                            });

         }

        如上述代码所示,可能从写法上大家会觉得有些奇怪,不过这就是AspectF的编写方式,可能看完后存在一些疑惑,但接下来我们分析后你将发现它确实很容易。首先AspectF.Define()是个静态方法,它返回了AspectF这个对象,这个对象是整个框架的核心。而代码中的Log和HowLong就是我们在外部定义的方面,而Do方法包含的内容就是我们应用这些方面的目标代码,整个代码是从左到右进行方面的调用的,形成了一条方面链。通过AspectF我们就可以在业务逻辑的外部定义方面的代码了,同时使业务更专注。在上述分析之后大家应该有了一个前期的理解了,之后我们将逐步介绍这些方面是如何进行定义的。

        在解释Aspects如何定义之前,我们先来看看AspectF的优势:

        (1)AspectF使得方面的定义更清晰,如果使用Attribute或者IL操作,这对用户而言是一个黑盒;

        (2)使用AspectF可以不用过度考虑性能的损失,因为它只是一个轻量级的类;

        (3)你可以向方面传递参数,而其它框架的AOP是不允许这么做的;

        (4)AspectF甚至不能称为一个框架,因为它只是一个叫做AspectF的类而已。

    如何在你的类中定义Aspects

        在这部分我们将介绍如何创建自己的aspects。首先你先为AspectF类创建一个扩展方法。例如我们将针对上例创建一个Log方面,如下面代码所示:

    public static AspectF Log(this AspectF aspect, TextWriter logWriter, string Message)
    {
        return aspect.Combine((work) =>
        {
            work();
            logWriter.Write(DateTime.Now.ToUniversalTime().ToString());
            logWriter.Write('\t');
            logWriter.Write(Message);
            logWriter.Write(Environment.NewLine);
        });
    }
        首先我们看看参数,AspectF指的是针对该调用方法的AspectF对象的本身,而后两个参数则是上例中我们传入的参数。我们再来看看方法内部的结构,你将调用AspectF对象的Combine方法把Log的内容编入AspectF的委托链中,其实在此部分Log的已经委托给了AspectF,当AspectF的Do方法被调用后,那么委托链上定义的方面都将按照从左到右的顺序依次执行。另外大家可能都注意到了work()这个方法调用,work是Action类型的,它表示的是我们的目标代码,对于上例来说就是客户信息插入的代码片段。 说到这里大家应该有了个比较直观的了解了吧。例子可能有些不全面,但是请大家自行阅读AspectF的源码和示例,相信会有很大收获的。

    总结

        可能有些对AOP方面非常熟悉的人在读完本篇文章后会有些争议,因为AspectF并没有呈现传统的AOP的特征,因为AOP在很对教材中的定义的核心是“关于”(concern)的分离和横截(cross-cutting),例如Spring.NET或者Struts2.0中包含的方法拦截,通过通知(notification)实现AOP。而AspectF确实没有进行横截的方法,但是它却实现了将“关于”的分离,可以说它具有AOP的特性,同时AscpectF的主要目标是创建独立的,脱离外部类库的程序,只需要使用AspectF对象,我们就可以轻松的创建新的方面,使用强类型和构建程序的新特性。

        总之AspectF相比框架真的很简单,可能笔者的描述有些一笔带过之嫌,还望见谅多多指点,总之希望大家能喜欢并多多支持,最后祝大家有个好心情!

  • 相关阅读:
    使用javap分析Java的字符串操作
    使用javap深入理解Java整型常量和整型变量的区别
    分享一个WebGL开发的网站-用JavaScript + WebGL开发3D模型
    Java动态代理之InvocationHandler最简单的入门教程
    Java实现 LeetCode 542 01 矩阵(暴力大法,正反便利)
    Java实现 LeetCode 542 01 矩阵(暴力大法,正反便利)
    Java实现 LeetCode 542 01 矩阵(暴力大法,正反便利)
    Java实现 LeetCode 541 反转字符串 II(暴力大法)
    Java实现 LeetCode 541 反转字符串 II(暴力大法)
    Java实现 LeetCode 541 反转字符串 II(暴力大法)
  • 原文地址:https://www.cnblogs.com/Leo_wl/p/1882114.html
Copyright © 2011-2022 走看看