博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
scala 学习笔记(06) OOP(下)多重继承 及 AOP
阅读量:6586 次
发布时间:2019-06-24

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

一、多继承

中,已经看到了其用法十分灵活,可以借此实现类似"多重继承"的效果,语法格式为:

class/trait A extends B with C with D ...

之所以要给多重继承加一个引号,是因为这有约束条件的,上面的语法中,从左向右看,extends 后的B是A的基本类型,不管后面接多少个trait,如果C或D,本身又继承自其它class(上一篇讲过,trait也可以继承自class),则C或D的基类必须与B的基类保持一致,否则的话,JVM上的OOP世界观将被彻底颠覆,scala编译出来的class,也就没办法与java兼容了,这个原则,我个人叫做『同宗同源』,很容易理解,必须认同共同的祖先!当然,如果C或D,本身只是纯粹的trait,不继承自其它任何类,这就相当于一个A继承自B,同时实现了多个接口,跟java中的理解一致。

package yjmyzz/** * 动物基类 */class Animal {}trait Fly {  println("4 -> Fly")  def fly}trait Swim {  def swim}class FlyAnimal extends Animal with Fly {  override def fly: Unit = println("I believe I can fly. I believe I can touch the sky")}trait FlyAndSwim extends Fly with Swim {}/** * 神基类 */class God {  println("1 -> God")}/* with关键字只能用于trait,而不能是classclass HalfGod extends God with Animal{  //Error:(14, 32) class Animal needs to be a trait to be mixed in  //class HalfGod extends God with Animal{}}*/trait Magic extends Animal {  def showMagic}/* 无效继承,因为HalfGod的基类为God,而magic的基类为Animal,它俩不是同一祖宗!class HalfGod extends God with magic {  //Error:(45, 32) illegal inheritance; superclass God  //  is not a subclass of the superclass Animal  //  of the mixin trait magic  override def showMagic: Unit = println("I have some magic!")}*/trait SuperPower {  println("2 -> SuperPower")  def superPower;}/** * "有超能力的"神 */class SuperPowerGod extends God with SuperPower {  println("3 -> SuperPowerGod")  override def superPower: Unit = println("I have super power!")}/** * "会飞的"神 */trait FlyGod extends God with Fly {  println("5 -> FlyGod")  override def fly: Unit = println("I can fly!")}/** * 多继承示例(SuperPowerGod与FlyGod都是God的子类,因此类型兼容,编译通过) */class MyGod extends SuperPowerGod with FlyGod {  println("6 -> MyGod")}object TestApp {  def main(args: Array[String]) {    var obj = new MyGod    /*    1 -> God    2 -> SuperPower    3 -> SuperPowerGod    4 -> Fly    5 -> FlyGod    6 -> MyGod    */  }}

代码略长,但是并不难理解。比较有意思的是构造函数的调用顺序,从输出结果看,大致遵循下面的原则:

1、先调用父类的构造器(即:extends B中B的构造器,如果B还有父类,则先向上找,直到找到最高层的父类,然后调用顶级父类的构造器)

2、然后再调用With后的Trait的构造器,

  a)如果Trailt本身继承自其它Class,则看下这个Class是不是步骤1中的父类,如果是的,就不重复调用了,最后输出的4 -> Fly 前,并没有重复输出1 -> God 就说明了这一点

  b) 调用Trait本身的构造器

3、上述过程反复处理,只到把所有层级的基类处理完

4、最后再调用本身的构造器

 

二、AOP

谈AOP之前,先来看看Scala的晚绑定:

package yjmyzztrait IA {  def foo = println("IA.foo()")}trait IAA extends IA{  override def foo = println("IAA.foo()")}class A extends IA{  override def foo = println("A.foo()")}object TestApp {  def main(args: Array[String]) {    val a = new A with IAA    a.foo    a.asInstanceOf[A].foo    a.asInstanceOf[IA].foo    a.asInstanceOf[IAA].foo  }}

最后的输出是:

IAA.foo()

IAA.foo()
IAA.foo()
IAA.foo()

即:不管实例a转型为什么类型,最终调用foo时,都是最底层的子类IAA里的foo方法,这就是晚绑定的特点。运行时,最底层的子类IAA已经override了父类的foo方法,所以最终不管怎么折腾,都是IAA里的override版本。

借助这个,就可以很方便的实现AOP,假设我们有一个业务处理类,想在业务处理前后,记录日志,这是典型的AOP方法拦截场景,看下面的示例代码:

package yjmyzz/** * 业务接口 */trait Handler {  def handle;}/** * 日志AOP */trait LoggerHandler extends Handler {  //注意这里的abstract不可省略,  //因为super.Handle并没有提供具体实现,而是在运行时,交由具体的子类来实现  abstract override def handle = {    println("log before handle...")    super.handle    println("log after handle...")  }}/** * 业务处理类 */class BizHandler extends Handler {  override def handle: Unit = println("business processing...")}object AopTest {  def main(args: Array[String]) {    var biz = new BizHandler with LoggerHandler;    biz.handle //这里实际上调用的是LoggerHandler.handle    //BizHandler为LoggerHandler的父类,所以运行时,    // LoggerHandler.handle中的super.Handle才是真正调用的BizHandler.handle方法  }}

输出结果:

log before handle...
business processing...
log after handle...

没有反射,没有动态代理,没有借助第3方类库,这是我见过的最简洁的AOP实现。

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

你可能感兴趣的文章
阿里云虚拟主机的使用,附幸运券领取
查看>>
数据库相关中间件收录集
查看>>
阿里云王坚:运营才能缔造真正的云计算
查看>>
C语言数据结构双向链表之温故而知新
查看>>
Java中类的创建及类与对象的关系
查看>>
大规模虚拟化,舍我其谁?
查看>>
“提速降费” 并非一蹴而就 矛头齐指运营商有失偏颇
查看>>
云计算99.9%可用性毫无意义 灾难恢复是关键
查看>>
生命科学研究需求推动云计算发展
查看>>
应用联合服务 云计算拉近应用和操作距离
查看>>
英国政府采用开源办公套件“GovOffice”
查看>>
赛门铁克分家前利润暴跌
查看>>
质数分布是否随机关乎安全大事
查看>>
高手云集 WCTF世界黑客大师赛今日开战
查看>>
JSR 303 - Bean Validation 介绍及最佳实践
查看>>
EVERTEC是如何利用大型机帮客户省钱?
查看>>
如何使用CHM 绕过Device guard
查看>>
vue中的组件
查看>>
Druid、C3P0、Tomcat Pool的性能测试与选型
查看>>
如何用PHP实现Socket服务器
查看>>