AOP, OOP, POP

POP: 注重功能性的实现,效果达到就好了

OOP: 注重封装,强调整体性的概念,将对象的内部组织与外部环境区分开来。

AOP: Aop 可以实现如事务,缓存,权限验证的功能。

复用代码:1. 继承的方式(纵向扩展)2. 组合/聚合(横向扩展,这就是AOP)

We may often see a particular lines of code becomes bigger as it grows, even up to the point where it becomes harder to understand its original business logic because the code already cluttered with other things, such as logging, authorization, validation, performance checker, etc.

但是随着软件开发的系统越来越复杂,工程师认识到,传统的OOP程序经常表现出一些不自然的现象,核心业务中总掺杂着一些不相关联的特殊业务,如日志记录,权限验证,事务控制,性能检测,错误信息检测等等,这些特殊业务可以说和核心业务没有根本上的关联而且核心业务也不关心它们。这样就会造成如下问题:

代码混乱:核心业务模块可能需要兼顾处理其他不相干的业务外围操作,这些外围操作可能会混乱核心操作的代码,而且当外围模块有重大修改时也会影响到核心模块,这显然是不合理的。

代码分散和冗余:同样的功能代码,在其他的模块几乎随处可见,导致代码分散并且冗余度高。

代码质量低扩展难:由于不太相关的业务代码混杂在一起,无法专注核心业务代码,当进行类似无关业务扩展时又会直接涉及到核心业务的代码,导致拓展性低。

显然前面分析的两种解决方案已束手无策了?,那么该如何解决呢?事实上我们知道诸如日志,权限,事务,性能监测等业务几乎涉及到了所有的核心模块,如果把这些特殊的业务代码直接到核心业务模块的代码中就会造成上述的问题,而工程师更希望的是这些模块可以实现热插拔特性而且无需把外围的代码入侵到核心模块中,这样在日后的维护和扩展也将会有更佳的表现,假设现在我们把日志、权限、事务、性能监测等外围业务看作单独的关注点(也可以理解为单独的模块),每个关注点都可以在需要它们的时刻及时被运用而且无需提前整合到核心模块中,这种形式相当下图:

每个关注点与核心业务模块分离,每份功能代码不再单独入侵到核心业务类的代码中。

这些外围业务会通过一种特殊的技术自动应用到核心模块中

adding additional behavior to existing code (an advice) without modifying the code itself

这些关注点有个特殊的名称,叫做“横切关注点”,上图也很好的表现出这个概念,另外这种抽象级别的技术也叫AOP(面向切面编程)

AOP面向切面编程(Aspect Oriented Programming)是通过预编译方式和运行期动态代理实现程序功能的统一维护的一种技术。

AOP的本质是通过代理对象来间接执行真实对象,在代理类中往往会添加装饰一些额外的业务代码

想在设置属性前后调用方法前后报错都能收集日志信息,将原有的真实类RealA委托给代理类ProxyRealA来执行,

拦截点(或者称为:横切面,切面点)一般主要为:执行前,执行后,发生错误

好处:核心代码部分在基类中,只专注于核心代码

新问题又来了,那就是当一个系统中的类非常多的时候,如果我们针对每个类都定义一个代理类,那么系统的类的个数会成倍增加,而且不同的代理类中可能某些拦截业务逻辑代码都是相同的

几种常见的实现AOP的方式:

一种是编译时静态植入,优点是效率高,缺点是缺乏灵活性,.net下postsharp为代表者(好像是付费了。。)。

另一种方式是动态代理,优点是灵活性强,但是会影响部分效率,动态为目标类型创建代理,通过代理调用实现拦截。

第一种:静态织入

编译器将代码注入到拦截点

PostSharp:PostSharp的Aspect是使用Attribute实现的。

我们只需事先通过继承自OnMethodBoundaryAspect,然后重写几个常见的方法即可,如:OnEntry,OnExit等,最后只需要在需要进行AOP拦截的属性或方法上加上AOP拦截特性类即可。

由于PostSharp是静态织入的,所以相比其它的通过反射或EMIT反射来说效率是最高的,但PostSharp是收费版本的,而且网上的教程比较多,我就不在此重复说明了。

第二种:EMIT反射

Emit反射动态生成代理类

如下Castle.DynamicProxy的AOP实现方式,代码也还是比较简单的,效率相对第一种要慢一点,但对于普通的反射来说又高一些

A command-line interface (CLI)

Autofac

相关术语:

组件:理解为容器内的基本单元,每个组件都有自己的信息:比如暴露的服务类型、生命周期域、绑定的具象对象等。

服务

不需要一个一个注册的,运用批量注册后容器内部的代码是这样的,可以直接批量注册所有的

注册方式

泛型注册:

builder.RegisterType();

Lambda注册: