博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
为什么要使用AOP?
阅读量:6239 次
发布时间:2019-06-22

本文共 4076 字,大约阅读时间需要 13 分钟。

在网上看到很多文章提到面向方面编程(Aspect-Oriented Programming),但一直没有搞清楚这样做有什么好处,为什么要使用AOP呢?

问题: 尽管面向对象编程与面向过程相比减少了代码的重复,但是它仍然留下了大量的重复代码。面向对象设计有助于最小化应用程序逻辑的代码重复,但是对于实现横切 关注点的代码仍然很难实现模块化,例如日志,虽然我们可以使用类似于log4Net这样的类库来灵活的记录日志, 但是记录日志的代码却遍布于程序之中,其中有大量的重复。

使用AOP却可以很好的解决这方面的问题。

举个例子来说明一下这个问题:

假设有一个账户类,里面有存钱和取钱的简单操作,如下  

    
///
 
<summary>
    
///
 账户类
    
///
 
</summary>
    
public
 
class
 Account 
    {
        
///
 
<summary>
        
///
 余额
        
///
 
</summary>
        
public
 
decimal
 Balance { 
get
set
; }        
        
///
 
<summary>
        
///
 存钱
        
///
 
</summary>
        
///
 
<param name="amount"></param>
        
public
 
void
 Deposit(
decimal
 amount)
        {
            
this
.Balance 
+=
 amount;
        }
        
///
 
<summary>
        
///
 取钱
        
///
 
</summary>
        
///
 
<param name="amount"></param>
        
public
 
void
 Withdraw(
decimal
 amount)
        {
            
this
.Balance 
-=
 amount;
        }

    } 

   

 现在需要记录一下日志,简单的方法如下,现在只是在Console中输出日志,实际项目中可能使用其它的日志模块来记录。

  
///
 
<summary>
        
///
 存钱
        
///
 
</summary>
        
///
 
<param name="amount"></param>
        
public
 
void
 Deposit(
decimal
 amount)
        {
            Console.WriteLine(
"
Start Deposit: 
"
 
+
 amount.ToString());
            
this
.Balance 
+=
 amount;
            Console.WriteLine(
"
End Deposit
"
);

        } 

 如果所有的方法都需要记录日志,则所有的方法需要像上面一样加上这些代码。

这种方法有很多问题: 

  1. 有大量的代码重复,不利于代码的长期维护。
  2. 核心代码和辅助日志代码混合在一起,日志代码分散了对方法核心逻辑的注意力,影响了方法的可读性。
  3. 如果需要移除日志代码,则面临着不小的工作量。
  4. 如果需要记录更多的信息,例如类名,则需要手工添加漏掉的类名。
  5. 如果决定记录异常,也面临着同样的问题,必须在很多地方重复记录。
使用像log4Net的类库来记录日志,虽然可以通过更改配置来关闭日志功能而不用修改任何代码,但是核心代码和辅助日志代码仍然混合在一起。

 使用AOP后, 我们可以将横切代码分离到几个方面中,而且很容易将这些方面应用于需要它们的类和方法上,除此之外, AOP还有大量的功能可以将业务规则从核心逻辑中分离出来。

下面来使用AOP来分离日志

修改后的代码如下     

    public interface IAccount
    {        
        
decimal
 Balance { 
get
set
; }
        
void
 Deposit(
decimal
 amount);    
    
        
void
 Withdraw(
decimal
 amount);
    }
    
public
 
class
 Account : Business.IAccount
    {
        
///
 
<summary>
        
///
 余额
        
///
 
</summary>
        
public
 
decimal
 Balance { 
get
set
; }        
        
///
 
<summary>
        
///
 存钱
        
///
 
</summary>
        
///
 
<param name="amount"></param>
        
public
 
void
 Deposit(
decimal
 amount)
        {
            
this
.Balance 
+=
 amount;
        }
        
///
 
<summary>
        
///
 取钱
        
///
 
</summary>
        
///
 
<param name="amount"></param>
        
public
 
void
 Withdraw(
decimal
 amount)
        {
            
this
.Balance 
-=
 amount;
        }

   } 

  除了Account类实现接口IAccount外,什么都没有变化。

 日志功能的实现如下:

    
public
 
class
 ConsoleLogAspect : IMethodInterceptor
    {
        
public
 
object
 Invoke(IMethodInvocation invocation)
        {
            Console.WriteLine(
"
-- Start {0} --
"
, invocation.Method.Name);
            
object
 returnValue 
=
 invocation.Proceed();
            Console.WriteLine(
"
-- End {0} --
"
, invocation.Method.Name);
            
return
 returnValue;
        }

    } 

 

客户端程序

    
class
 Program
    {
        
static
 
void
 Main(
string
[] args)
        {
            IApplicationContext ctx 
=
 ContextRegistry.GetContext();
            IAccount account 
=
 (IAccount)ctx.GetObject(
"
MyAccount
"
);
            account.Balance 
=
 
10
;            
            account.Deposit(
15
);
            account.Withdraw(
20
);
            Console.ReadKey();
        }

    } 

 注意:代码中客户端程序只使用接口,不使用Account类

配置文件内容, 通过配置文件来配置IAccount。

 <configuration>

    
<
configSections
>
        
<
sectionGroup name
=
"
spring
"
>
            
<
section name
=
"
context
"
 type
=
"
Spring.Context.Support.ContextHandler, Spring.Core
"
 
/>
            
<
section name
=
"
objects
"
 type
=
"
Spring.Context.Support.DefaultSectionHandler, Spring.Core
"
 
/>
        
</
sectionGroup
>
    
</
configSections
>
    
<
spring
>
        
<
context
>
            
<
resource uri
=
"
config://spring/objects
"
/>
        
</
context
>
        
<
objects xmlns
=
"
http://www.springframework.net
"
 
>
            
<
object
 id
=
"
ConsoleLogAspect
"
 type
=
"
Spring.Aop.Support.NameMatchMethodPointcutAdvisor, Spring.Aop
"
>
                
<
property name
=
"
Advice
"
>
                    
<
object
 type
=
"
Aspects.ConsoleLogAspect, Aspects
"
 
/>
                
</
property
>
                
<
property name
=
"
MappedNames
"
>
                    
<
list
>
                        
<
value
>
Deposit
</
value
>
                        
<
value
>
Withdraw
</
value
>
                    
</
list
>
                
</
property
>
            
</
object
>
            
<
object
 id
=
"
MyAccount
"
 type
=
"
Spring.Aop.Framework.ProxyFactoryObject
"
>
                
<
property name
=
"
Target
"
>
                    
<
object
 type
=
"
Business.Account, Business
"
 
/>
                
</
property
>
                
<
property name
=
"
InterceptorNames
"
>
                    
<
list
>
                        
<
value
>
ConsoleLogAspect
</
value
>
                    
</
list
>
                
</
property
>
            
</
object
>
        
</
objects
>
    
</
spring
>
</
configuration
>

 运行结果:

aop1.PNG 

 日志已经被记录下来了。

 对比一下使用AOP的好处: 

  1. 核心代码中不在包含记录日志的代码, 类更专注于它的职责。
  2. 如果想修改日志的记录方式, 不需要修改Account类,只需要修改相应的配置文件和日志的实现,修改工作量小。
  3. 使用这种方式可以动态的修改业务规则而不用修改Account类, 也不用重新编译发布。例如Account.WithDraw()方法的核心是减少账户余额,假设程序布署后客户又来一新的需求,当账户余额小于50元时, 发邮件通知客户,此时只需要像添加日志一样实现这一功能,配置到程序上去就好了。最适合移入方面的业务规则是那些在实现核心逻辑的同时也需要实现的二级逻 辑的规则。
  4. 实现AOP的同时需要依赖注入, 这又会减少模块间的依赖。
  5. 依赖注入要用到Ioc容器, 这个又可以代替工厂类,这算是又一个好处吧

 大家觉得呢?

下载 

转载地址:http://cvdia.baihongyu.com/

你可能感兴趣的文章
【转】深入理解 C# 协变和逆变
查看>>
第六次作业
查看>>
UML
查看>>
9.[Java开发之路](6)File类的使用
查看>>
折半插入排序(binary insertion sort)
查看>>
打包常见问题
查看>>
javascript解析json
查看>>
在Ubuntu下编译WebKit源码
查看>>
amazeui 移动开发
查看>>
python2 与python3中最大的区别(编码问题bytes&str
查看>>
HDU 2243 AC自动机+DP+矩阵
查看>>
什么叫脱字符合^
查看>>
git版本控制管理实践-2
查看>>
HTTP基础知识(三)
查看>>
如何有效释放DB2所占的磁盘空间?
查看>>
三分法
查看>>
第 8 章 容器网络 - 058 - flannel 概述
查看>>
Mongodb删除collection
查看>>
ArcEngine应用程序中无法实现TOC图层多选
查看>>
Java-笔记9-复习
查看>>