这只是一篇入门理解!
一直听说AOP的名字,却从未使用过,因为我不会。但……那只是曾经……
先看官方解释:AOP(Aspect-Oriented Programming,面向切面的编程),它是可以通过预编译方式和运行期动态代理实现在不修改源代码的情况下给程序动态统一添加功能的一种技术。它是一种新的方法论,它是对传统OOP编程的一种补充。OOP是关注将需求功能划分为不同的并且相对独立,封装良好的类,并让它们有着属于自己的行为,依靠继承和多态等来定义彼此的关系;AOP是希望能够将通用需求功能从不相关的类当中分离出来,能够使得很多类共享一个行为,一旦发生变化,不必修改很多类,而只需要修改这个行为即可。AOP是使用切面(aspect)将横切关注点模块化,OOP是使用类将状态和行为模块化。在OOP的世界中,程序都是通过类和接口组织的,使用它们实现程序的核心业务逻辑是十分合适。但是对于实现横切关注点(跨越应用程序多个模块的功能需求)则十分吃力,比如日志记录,权限验证,异常拦截等。
看完是不是很迷?不懂的人看不懂,懂得人不用看。
当我明白什么是面向切面后,我想到了一个故事——横切的苹果(这里不讲故事内容)。我们大多数人都是切苹果的方式,和我们的代码排版是一样的--竖的。就像这样:
public void Test1() { console.writeline("执行前日志"); do(); console.writeline("执行后日志"); } public void Test2() { console.writeline("执行前日志"); do(); console.writeline("执行后日志"); } public void Test3() { console.writeline("执行前日志"); do(); console.writeline("执行后日志"); }
但是总会有人去横着切苹果,然后发现了苹果里的五角星(现在苹果贵,网图凑合一下):
我们把代码也横排版一下:
public void Test1() public void Test1() public void Test1() { { { console.writeline("前");console.writeline("前");console.writeline("前") do(); do(); do(); console.writeline("后");console.writeline("后");console.writeline("后") } } }
会发现出现大量重复的功能性代码(日志、验证等)出现在代码里,AOP就是把这些函数里可统一、可通用的代码都抽离出来,统一调用,统一修改,避免了每次修改这些代码时,大量重复的修改工作以及一些没必要的BUG,这就是面向切面。
一切不写demo的博客都是耍流氓!
这里用Postsharp来写demo,先去官网https://www.postsharp.net/下载一个安装包,申请免费许可证书,然后安装即可。
先把需要抽离的代码写在一个类里,上面的代码用writeline代替写日志,do()代替各自不同的业务代码。
[Serializable] public class TestAopAspect : OnMethodBoundaryAspect {//必须是Serializable 必须继承 OnMethodBoundaryAspect //执行前 可验证参数 或执行前日志等 public override void OnEntry(MethodExecutionArgs args) { Console.WriteLine($"{args.Arguments[0]}执行前"); } //成功执行后 public override void OnSuccess(MethodExecutionArgs args) { Console.WriteLine($"{args.Arguments[0]}执行后"); } }
然后写实现方法:
static void Main(string[] args) { Test1("Test1"); Test2("Test2"); Test3("Test3"); Console.ReadKey(); } [TestAopAspect] static void Test1(string msg) { Do(msg); } [TestAopAspect] static void Test2(string msg) { Do(msg); } [TestAopAspect] static void Test3(string msg) { Do(msg);//只有业务代码,没有写重复的功能代码 } static void Do(string msg) { Console.WriteLine($"{msg},我就是我,不一样的烟火!"); }
看看执行结果:
//如果后续对日志内容或者验证做变更,也不需要在所有的Test方法里做修改,只需要在TestAopAspect里修改即可。
怎么能不反编译一下,看看发生了什么呢?
原来是postsharp在编译时替我们写了那些代码,至于专业术语,他们说是编织就是编织咯。