Scala 堆叠Traits实现对方法的增强

Scala 堆叠Traits实现对方法或函数的增强

简单的来说,堆叠Trait类似于AOP,实现对方法功能的增强,而不去修改原有方法的逻辑。

比如我们实现一个队列,我们可以定义一个队列的抽象类,实现入队和出队操作,用scala这样写,和java差不多,


abstract class IntQueue {
  def get(): Int

  def put(x: Int)
}

我们去实现这个抽象类,

class BasicIntQueue extends IntQueue {
  private val buf = new ArrayBuffer[Int]

  override def get() = buf.remove(0)

  override def put(x: Int) {
    buf += x
  }
}

测试一下,

object Main87 {
  def main(args: Array[String]) {
    val queue = new BasicIntQueue
    queue.put(10)
    queue.put(20)
    println(queue.get())
    println(queue.get())
  }
}

这样是可以实现我们的功能的。但是我们想在put方法上实现更多的功能,比如说给入队的值加倍。

你可能会说直接去修改put方法的逻辑,这样也是可行的,但没有扩展性。比较好的方法还可以是继承父类在实现一个具体的类,put方法的逻辑是加倍。

class BasicIntQueue2 extends IntQueue {
  private val buf = new ArrayBuffer[Int]

  override def get() = buf.remove(0)

  override def put(x: Int) {
    buf += 2 * x
  }
}

如果现在逻辑又改了,我们要过滤入队的值,比如说值小于等于0 ,那么丢弃,不入队,然后把过滤后的值加倍。这样的话是不是还要实现一个具体的类,实现这样的逻辑?当然可以这么做。然而在java中,运用AOP的思想可以给put方法写一个切面,作用于加倍的put方法。加逻辑,就要写切面,这样也不是很好。在scala中实现这样的功能就是堆叠trait。

我们定义加倍的Trait,

trait Doubling extends IntQueue {
  abstract override def put(x: Int) {
    println("doubling")
    super.put(2 * x)
  }
}

定义过滤的Trait,

trait Filtering extends IntQueue {
  abstract override def put(x: Int) {
    println("filtering")
    if (x >= 0) super.put(x)
  }
}

这两个trait相当于一个一个的切面,如何把这些逻辑加到基础的put方法上呢?我们可以这样来做

class MyQueue00 extends BasicIntQueue with Doubling with Filtering

object Main87 {
  def main(args: Array[String]) {
    val q = new MyQueue00
    q.put(-1)
    q.put(0)
    q.put(1)
    println(q.get())
    println(q.get())
  }
}

运行结果,

filtering

filtering

doubling

filtering

doubling

0

2

这个问题就这么优雅的解决了,这样做的好处就是可以很好的复用代码。

一个完成的demo

package com.usoft4

import scala.collection.mutable.ArrayBuffer

abstract class IntQueue {
  def get(): Int

  def put(x: Int)
}

class BasicIntQueue extends IntQueue {
  private val buf = new ArrayBuffer[Int]

  override def get() = buf.remove(0)

  override def put(x: Int) {
    buf += x
  }
}

class BasicIntQueue2 extends IntQueue {
  private val buf = new ArrayBuffer[Int]

  override def get() = buf.remove(0)

  override def put(x: Int) {
    buf += 2 * x
  }
}

trait Doubling extends IntQueue {
  abstract override def put(x: Int) {
    println("doubling")
    super.put(2 * x)
  }
}

trait Incrementing extends IntQueue {
  abstract override def put(x: Int) {
    println("incrementing")
    super.put(x + 1)
  }
}

trait Filtering extends IntQueue {
  abstract override def put(x: Int) {
    println("filtering")
    if (x >= 0) super.put(x)
  }
}

class MyQueue0 extends BasicIntQueue with Doubling

class MyQueue00 extends BasicIntQueue with Doubling with Filtering

object Main87 {
  def main(args: Array[String]) {
    val queue = new BasicIntQueue
    queue.put(10)
    queue.put(20)
    println(queue.get())
    println(queue.get())

    val q = new MyQueue00
    q.put(-1)
    q.put(0)
    q.put(1)
    println(q.get())
    println(q.get())

    val myQueue = new MyQueue0
    myQueue.put(10)
    println(myQueue.get())

    val myQueue2 = (new BasicIntQueue with Filtering with Incrementing)
    myQueue2.put(-1)
    println("put end")
    myQueue2.put(0)
    println("put end")
    myQueue2.put(1)
    println("put end")
    println(myQueue2.get())
  }
}

=====================END=====================

时间: 2024-11-10 07:47:25

Scala 堆叠Traits实现对方法的增强的相关文章

自己实现简单的AOP(二)引入Attribute 为方法指定增强对象

话续前文 : 自己实现简单的AOP(一)简介 在第一篇文章中,对AOP的实现方式做了一个简单介绍.接下来,引入Attribute 为方法指定增强对象,由此实现一个简单的AOP. 注意:指定的是增强对象,“对象”,也就是说Attribute标记,标记的其实是一个对象.由此.使用多态便可轻松实现增强的扩展. 自定义的Attribute /// <summary> /// 为方法标记指定的增强对象 /// <para>指定的增强,可通过代理 DelayProxy 织入</para&

Desugar Scala(15) -- unapply和unapplySeq方法

欢迎关注我的新博客地址:http://cuipengfei.me/ 实在想不到什么动词可以当做脱衣服来讲了,所以从现在开始这系列博文就叫做Desugar Scala了.除非哪天才思泉涌,又想到了新词:) 开始正文. 名字叫做unapply和unapplySeq的方法在Scala里也是有特殊含义的. 我们前面说过case class在做pattern match时很好用,而除case class之外,有unapply或unapplySeq方法的对象在pattern match时也有很好的应用场景.

VBA 一个find方法的增强函数

'本函数是一个find方法的增强函数,结合FindNext和FindPrevious方法,可以返回一组符合条件的单元格的集合: '本函数返回一个Collection对象,里面储存了找到的单元格: '本函数有两个必选参数: ' 1.SearchRange 用来存放需要查找的区域: ' 2.FindWhat用来存放需要查找的值; '其余参数都是可选参数,与Find方法参数相同: '无论是否查找到单元格,都会返回一个collection对象: '我们用Collection.Count=0,来判断,没有

scala学习手记34 - trait方法的延迟绑定

trait的方法的延迟绑定就是先混入的trait的方法会后调用.这一点从上一节的实例中也可以看出来. 下面再来看一个类似的例子: abstract class Writer { def write(message: String): String } trait UpperWriter extends Writer { abstract override def write(message: String): String = super.write(message.toUpperCase) }

Scala之Traits

一.前言 前面学习了Scala中包和导入的相关知识点,接着学习Traits(特质) 二.Traits Scala的特质与Java的接口基本相同,当遇到可以使用Java接口的情形,就可以考虑使用特质,Scala的类可以使用extends和with关键字继承多个特质,如类或对象继承多个特质 class Woodpecker extends Bird with TreeScaling with Pecking 特质除了可以拥有Java中接口的抽象方法,同时还可以拥有已经实现的方法,可以将多余一个的特质

发现一个类的方法不够用时,可以使用的3种方法可以增强

A.创建子类,改写需要增强的方法B.包装设计模式//1.定义一个类,实现与被增强对象相同的接口//2.在类中定义一个变量,记住被增强对象//3.定义一个构造对象,接受被增强对象//4.覆盖想增强的方法//5.对于不想增强的方法,直接调用目标对象的方法C.使用动态代理(aop面向切面编程) //视频讲解: 方立勋javaweb30天教程-就业办16/day16avi/03-数据库连接池.avi https://pan.baidu.com/s/1eQBvrRc#list/path=%2F%E6%96

scala入门-02基础知识-&gt;方法

首先在src下的main下的scala下创建一个包为org.scala.base 创建一个scala类名称为HelloWorld.scla 由于main方法要位于object对象中,所以我们创建一个object 名称为HelloWorld 并增加main方法和打印一行内容 接下来 我们在object对象中增加一个方法:printlnHello; PS: 1.函数体的最后一行的值就是整个函数的返回值 2.类型的申明是位于变量或者函数或者类的后面 另一种方式定义方法: 当方法or 函数是无参数时候,

scala类型推断及库方法设计原则和==与java有何差别

scala类型推断 方法msortSwapped(abcd)(_>_) 通常,一旦有需要推断多台方法类型参数的任务时,类型推断器就只参考第一个参数列表中所有参数类型,但不会参考之后其他参数.因为方法msortSwapped是柯里化的方法,带两个参数列表,所以第二个参数(也就是说,那个函数值)将不会用来做决定方法参数的参考. 因此这种类型推断方案也隐含了如下库方法设计原则:如果需要把参数设计为若干非函数值及一个函数值的某种多态方法,需要把函数参数放在柯里化参数列表的最后面.这样一来,方法的正确类型

Spark Scala 读取GBK文件的方法

1. 在生产环境下,很多文件是GBK编码格式的,而SPARK 常用的textFile方法默认是写死了读UTF-8格式的文件,其他格式文件会显示乱码 用如下代码实现读取GBK文件的方法 import org.apache.hadoop.io.{LongWritable, Text}import org.apache.hadoop.mapred.TextInputFormatimport org.apache.spark.rdd.RDDimport org.apache.spark.{SparkCo