![bac6926b634e0f11ec3a9756d7755b0f.png](https://i-blog.csdnimg.cn/blog_migrate/0190ac090c20bf95f34002735ee9fe22.jpeg)
AOP面向切面编程
先上概念
不管你是否能看懂,了解一下概念还是有必要的。
AOP是OOP的延续,是Aspect Oriented Programming的缩写,直译意思:面向方面编程、面向切面编程。
AOP通过预编译方式和运行期动态代理实现在不修改源代码的情况下给程序动态统一添加功能的一种技术。可以在代码阶段实现分离关注,实现松耦合,然后在运行时将相关动作特征植入运行,从而改变程序的运行顺序,达到拦截或者增加功能的目的。
AOP的好处
解耦:AOP将程序中的共性问题进行了剥离,毫无疑问地降低了各个业务模块和共性问题之间的耦合。
重用性:共性问题散落于业务逻辑的各处,十分难维护,使用AOP进行提取后,能够将相似功能的共性问题收敛,减少重复代码,提高了代码的重用性。
拓展性:对于一个程序而言,迭代的重心一定在于业务和功能上。AOP使得每当发生变更时,可以只关注业务逻辑相关的代码,而减少共性问题上带来的变化,大大降低了程序未来拓展的成本。
生活中的AOP
第一次接触的人是会有一点蒙圈,要理解AOP(面向切面编程),首先我们要明白什么叫做切面,下面举个生活中的小例子。
厨师做菜的步骤是:拿菜、洗菜、切菜、做菜,这个是主干流程。
有一天公司老板说需要给所有厨师统计工作量,一天做了几个菜都记录好,有两种方式:
方法1:厨师做菜完毕后拿起一张纸,每做好一个菜就纸上做一个标记。
方法2:厨师做菜完毕通知另外一个负责登记的同事,让同事来做登记,这个就是Aop。
那么Aop的好处是什么呢?
可以让厨师专注于做菜这个主干流程,而不需要去做其他不相干的事情。
程序中的Aop
我们最常用场景是:日志功能,下面定义一个日志类。
public class Log { public void WriteLog() { //写日志 } }
需求是:用户登录、注册等所有操作都需要记录日志,传统写法如下:
/// /// 注册类 /// public class Reg { public void MemberReg() { //注册的逻辑省略.... Log log = new Log(); log.WriteLog(); } } /// /// 登录类 /// public class Login { public void MemberLogin() { //登录的逻辑省略.... Log log = new Log(); log.WriteLog(); } } //其他100个类省略....
这样写看起来是没有问题,当某一天,客户说日志需要记录用户操作时候用的浏览器型号,负责日志的同事把日志类改为:
public class Log { public void WriteLog(string borwerType) { //写日志 } }
那之前的代码都要改为:
/// /// 注册类 /// public class Reg { public void MemberReg() { //注册的逻辑省略.... Log log = new Log(); log.WriteLog("IE浏览器"); } } /// /// 登录类 /// public class Login { public void MemberLogin() { //登录的逻辑省略.... Log log = new Log(); log.WriteLog("谷歌浏览器"); } } //其他100个类省略....
如果几个还好说,如果涉及的项目比较大,就是几百个文件都要修改,我估计你要崩溃。
那么如何使用Aop的方式改造呢?
使用基类继承来改造
先定义个基类,把写日志的方法定义在基类中
public class BaseClass { public void WriteLog() { string borwerType = "获取浏览器的省略...."; Log log = new Log(); log.WriteLog(borwerType); } ...其他方法 }
其他需要日志功能的类继承这个基类,如下:
/// /// 注册类 /// public class Reg: BaseClass { public void MemberReg() { //注册的逻辑省略.... base.WriteLog(); } } /// /// 登录类 /// public class Login : BaseClass { public void MemberLogin() { //登录的逻辑省略.... base.WriteLog(); } }
以后如果有日志需要变化,只需要更改BaseClass中的方法即可,我个人不推荐这种做法,编程有一个重要原则是:多用组合,少用继承。
c#和Java都不支持多基类继承,这就会导致如果后期有很多类似日志这种辅助性功能多的时候,基类就会无限膨胀,而且导致继承了很多不需要的方法。
使用特性来改造
我强烈推荐这种用法,使用过asp.net mvc的小伙伴都知道mvc有一个拦截器,就是通过特性的原理来实现,下面把日志类改造为特性,如下:
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, Inherited = true)] public class LogAttribute : ActionFilterAttribute { public override void OnActionExecuted(ActionExecutedContext filterContext) { //写日志 } }
在需要日志功能的类或方法上加上特性标记,改造后的代码如下:
/// /// 注册类 /// public class Reg { [Log] public void MemberReg() { //注册的逻辑省略.... } } [Log] public class Login { public void MemberLogin() { //登录的逻辑省略.... } }
特性可以用在类上,也可以用到方法上。
这样改造后是不是觉得代码瞬间简洁很多,以后日志需求更改,只需要更改日志类就可以了。
好了,先说到这里,欢迎大家转发和关注我后续的文章。