OOP与AOP的区别和联系

一、OOP及AOP的定义
1.OOP
面向对象程序设计(Object Oriented Programming),其本质是以建立模型体现出来的抽象思维过程和面向对象的方法。特点是封装、继承、多态、抽象。
①封装:把描述一个对象的属性和行为的代码封装在一个模块中,也就是一个类中,属性用变量定义,行为用方法定义,方法可以直接访问同一个对象的属性
②抽象:把现实生活中的对象抽象为类。分为过程抽象和数据抽象。
③继承:子类继承父类的特征和行为。子类可以有父类的方法,属性(非private)。子类也可以对父类进行扩展,也可以重写父类的方法。缺点是提高了代码的耦合性。、
④多态:指程序中定义的引用变量所指向的具体类型和通过该引用变量发出的方法调用在编程时并不确定。而是在程序运行期间才确定(比如:向上转型,只有运行才能确定其对象属性)。方法覆盖和重载体现了多态性。
2.AOP
AOP为Aspect Oriented Programming的缩写,意为:面向切面编程,通过预编译方式和运行期动态代理实现程序功能的统一维护的一种技术
二、区别
AOP、OOP在字面上虽然非常类似,但却是面向不同领域的两种设计思想。OOP(面向对象编程)针对业务处理过程的实体及其属性和行为进行抽象封装,以获得更加清晰高效的逻辑单元划分。
而AOP则是针对业务处理过程中的切面进行提取,它所面对的是处理过程中的某个步骤或阶段,以获得逻辑过程中各部分之间低耦合性的隔离效果。这两种设计思想在目标上有着本质的差异。

①面向目标不同:简单来说 OOP 是面向名词领域,AOP 面向动词领域。
②思想结构不同:OOP 是纵向结构,AOP 是横向结构。
③注重方面不同:OOP 注重业务逻辑单元的划分,AOP 偏重业务处理过程中的某个步骤或阶段。
纵向关系 OOP,横向角度 AOP
举个小例子:
设计一个日志打印模块。按 OOP 思想,我们会设计一个打印日志 LogUtils 类,然后在需要打印的地方引用即可。

public class ClassA {
    private void initView() {
        LogUtils.d(TAG, "onInitView");
    }
}

public class ClassB {
    private void onDataComplete(Bean bean) {
        LogUtils.d(TAG, bean.attribute);
    }
}

public class ClassC {
    private void onError() {
        LogUtils.e(TAG, "onError");
    }
}

看起来没有任何问题是吧?

但是这个类是横跨并嵌入众多模块里的,在各个模块里分散得很厉害,到处都能见到。从对象组织角度来讲,我们一般采用的分类方法都是使用类似生物学分类的方法,以「继承」关系为主线,我们称之为纵向,也就是 OOP。设计时只使用 OOP思想可能会带来两个问题:

①对象设计的时候一般都是纵向思维,如果这个时候考虑这些不同类对象的共性,不仅会增加设计的难度和复杂性,还会造成类的接口过多而难以维护(共性越多,意味着接口契约越多)。
②需要对现有的对象 动态增加 某种行为或责任时非常困难。

而AOP就可以很好地解决以上的问题,怎么做到的?除了这种纵向分类之外,我们从横向的角度去观察这些对象,无需再去到处调用 LogUtils 了,声明哪些地方需要打印日志,这个地方就是一个切面,AOP 会在适当的时机为你把打印语句插进切面。

// 只需要声明哪些方法需要打印 log,打印什么内容
public class ClassA {
    @Log(msg = "onInitView")
    private void initView() {
    }
}

public class ClassB {
    @Log(msg = "bean.attribute")
    private void onDataComplete(Bean bean) {
    }
}

public class ClassC {
    @Log(msg = "onError")
    private void onError() {
    }
}

如果说 OOP 是把问题划分到单个模块的话,那么 AOP 就是把涉及到众多模块的某一类问题进行统一管理。AOP的目标是把这些功能集中起来,放到一个统一的地方来控制和管理。利用 AOP 思想,这样对业务逻辑的各个部分进行了隔离,从而降低业务逻辑各部分之间的耦合,提高程序的可重用性,提高开发效率。
OOP与AOP的区别和联系_第1张图片
三、联系
两者之间是一个相互补充和完善的关系。
那AOP既然这么有用,除了上面提到的打印日志场景,还有没有其他用处呢?

当然有!

只要系统的业务模块都需要引用通用模块,就可以使用AOP。以下是一些常用的业务场景:

  1. 参数校验和判空
    系统之间在进行接口调用时,往往是有入参传递的,入参是接口业务逻辑实现的先决条件,有时入参的缺失或错误会导致业务逻辑的异常,大量的异常捕获无疑增加了接口实现的复杂度,也让代码显得雍肿冗长,因此提前对入参进行验证是有必要的,可以提前处理入参数据的异常,并封装好异常转化成结果对象返回给调用方,也让业务逻辑解耦变得独立。

  2. Android API23+的权限控制
    避免到处都是申请权限和处理权限的代码

  3. 无痕埋点

  4. 安全控制
    比如全局的登录状态流程控制。

  5. 日志记录

  6. 事件防抖
    防止View被连续点击触发多次事件

  7. 性能统计
    检测方法耗时其实已经有一些现成的工具,比如 trace view。痛点是这些工具使用起来都比较麻烦,效率低下,而且无法针对某一个块代码或者某个指定的sdk进行查看方法耗时。可以采用 AOP 思想对每个方法做一个切点,在执行之后打印方法耗时。

  8. 事务处理
    声明方法,为特定方法加上事务,指定情况下(比如抛出异常)回滚事务

  9. 异常处理
    替代防御性的 try-Catch。

  10. 缓存
    缓存某方法的返回值,下次执行该方法时,直接从缓存里获取。

  11. 软件破解
    使用 Hook 修改软件的验证类的判断逻辑。

  12. 热修复
    AOP 可以让我们在执行一个方法的前插入另一个方法,运用这个思路,我们可以把有 bug 的方法替换成我们下发的新方法。

作者:FeelsChaotic
链接:https://www.jianshu.com/p/0799aa19ada1
来源:简书

你可能感兴趣的:(java编程思想,aop,java)