前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >scala 学习笔记(06) OOP(下)多重继承 及 AOP

scala 学习笔记(06) OOP(下)多重继承 及 AOP

作者头像
菩提树下的杨过
发布2018-01-18 17:38:32
1K0
发布2018-01-18 17:38:32
举报
文章被收录于专栏:菩提树下的杨过

一、多继承

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

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中的理解一致。

代码语言:javascript
复制
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,而不能是class
class 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的晚绑定:

代码语言:javascript
复制
package yjmyzz

trait 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方法拦截场景,看下面的示例代码:

代码语言:javascript
复制
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实现。

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2015-08-16 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档