在上一节看到了scala的在实例一级的选择性混入就不得不感叹scala在语法上的扩展性。就通过这样一个特性scala简化了很多在java中的编程概念和设计模式。

比如说在java中常用的组合,以及装饰模式。下面看个书中的例子,详细说说如何使用trait进行装饰。

假设我们要对一个人进行检查,包括信用记录、收支记录、犯罪记录和工作记录等。但是我们并不会总是都会用到所有的检查,比如要买房时会检查信用记录和收支记录,申请出境时会检查犯罪记录和工作记录。

想想该怎么做:最简单的思路是为每种检查创建一个方法,然后在需要的时候将这些方法组合起来。更常用的方案是创建一个检查接口,为每种检查创建一个类,并实现检查方法。为基础的检查,比如信用记录、收支记录创建检查等创建一个基础类还是可行的,但是如果要为每一项具体的检查创建一个类就会面临一个问题:类膨胀。scala可以让我们避免这种问题,使用trait混入实例可以实现面对不同的检查提供不同的处理方案这样的灵活性。

首先我们需要定义一个抽象类Checker,实现一些在检查中的通用的行为:

abstract class Check {
def check(): String = "Checked Application Details..."
}

然后为每一类基础性的检查创建一个trait

trait CreditCheck extends Check {
override def check(): String = "Checked Credit..." + super.check()
} trait BalanceCheck extends Check{
override def check(): String = "Checked Balance..." + super.check()
} trait EmploymentCheck extends Check {
override def check(): String = "Checked Employment..." + super.check()
} trait CriminalRecordCheck extends Check {
override def check(): String = "Check Criminal Records..." + super.check()
}

这些trait都继承自Check。因为我们只想把它混入继承自Check的类。这样做有两个好处:这些trait只能混入继承自Check的类;这些trait可以使用Check的方法。

在每个trait里,都重写了check方法,在重写的同时也引用了Check类的方法,这也可以说是对Check类的修饰或增强。

trait里,通过super调用的方法会经历一个延迟绑定的过程。这个调用并不是对基类的调用,而是对其左边混入的trait的调用——如果这个trait已经是混入的最左trait,那么这个调用就会解析成混入这个trait的类的方法。具体如何可以看一下下面的例子是如何实现的。

来看一个买房申请:

val apartmentApplication = new Check with CreditCheck with BalanceCheck

println(apartmentApplication check)

在创建Check实例的同时混入了两个trait:CreditCheck和BalanceCheck。同样的也可以这样实现出境申请:

val exitApplication = new Check with CriminalRecordCheck with EmploymentCheck

println(exitApplication  check)

可以看出,如果想要按照不同的组合进行检查的话,只需要按照希望的组合将trait混入即可。

上面两段代码的执行结果如下:

最右的trait开始调用check()。然后,顺着super.check(),将调用传递到其左边的trait。最左的trait调用的是真正实例的check()。

在Scala里,trait是一个强有力的工具,可以用它混入横切关注点。使用它们可以以较低的成本创建出高度可扩展的代码。无需创建一个拥有大量类和接口的层次结构,就可以快速地把必要的代码投入使用。

###########

scala学习手记33 - 使用trait进行装饰的更多相关文章

  1. scala学习手记31 - Trait

    不知道大家对java的接口是如何理解的.在我刚接触到接口这个概念的时候,我将接口理解为一系列规则的集合,认为接口是对类的行为的规范.现在想来,将接口理解为是对类的规范多少有些偏颇,更恰当些的观点应该是 ...

  2. Spark基础-scala学习(三、Trait)

    面向对象编程之Trait trait基础知识 将trait作为接口使用 在trait中定义具体方法 在trait中定义具体字段 在trait中定义抽象字段 trait高级知识 为实例对象混入trait ...

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

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

  4. scala学习手记32 - trait选择性混入

    继续上一节. 狗当然是人类的好朋友.但是藏獒呢?这玩意儿又蠢又笨又凶狠,肯定不能算很多人的好朋友了.其实,刚才那句话还可以修正一下下:我们接受的狗才是我们的好朋友. 用程序怎么实现呢?在java里面, ...

  5. scala学习笔记-面向对象编程之Trait

    将trait作为接口使用 1 // Scala中的Triat是一种特殊的概念 2 // 首先我们可以将Trait作为接口来使用,此时的Triat就与Java中的接口非常类似 3 // 在triat中可 ...

  6. scala学习手记40 - 使用case类

    前面两节我们已经多次接触过case关键字了.case关键字不仅可以用在match/case中来执行模式匹配,也可以用来修饰类.不过用case修饰的类也主要是用来做模式匹配.在上一节曾经提到过match ...

  7. scala学习手记38 - 方法命名约定和for表达式

    方法命名约定 之前在学习<运算符重载>一节时曾经说过一个方法命名约定:方法的第一个字符决定了方法的优先级.现在再说另一个命名约定:如果方法以冒号(:)结尾,则调用目标是运算符后面的实例. ...

  8. scala学习手记23 - 函数值

    scala的一个最主要的特性就是支持函数编程.函数是函数编程中的一等公民:函数可以作为参数传递给其他函数,可以作为其他函数的返回值,甚至可以在其它函数中嵌套.这些高阶函数称为函数值. 举一个简单的例子 ...

  9. scala学习手记17 - 容器和类型推断

    关于scala的类型推断前面已经提到过多次.再来看一下下面这个例子: import java.util._ var list1: List[Int] = new ArrayList[Int] var ...

随机推荐

  1. TADDConnetion组件,TADOQuery

    一.TADDConnetion 二.TADOQuery 1.RecNo:从1开始 当前记录行数;ADOQuery1.RecNo 选择后一行数据集内容:ADOQuery1.RecNo:=ADOQuery ...

  2. python将图片转base64,前端显示

    https://blog.csdn.net/u013055678/article/details/71406746 <img src='xxxxxxx'> 跟这样的效果是一样的吧?     ...

  3. CSS 快速入门

    特点: CSS 将网页内容和显示样式进行分离,提高了显示效果的功能. CSS 和 html 相结合的四种方式: style 属性的方式 每个 html 标签中都有一个 style 样式属性, 该属性的 ...

  4. java maven项目打包

    使用IDEA打包,首先调出来maven projects窗口: 菜单栏Help->Find Action(Ctrl+Shift+A),输入Maven projects https://blog. ...

  5. Win10 jdk的安装以及环境变量的配置,及需要注意的坑

    此篇文章献给自己,希望下次长点记性 最近本人终于有时间开始学习appium,并且开始在电脑上配置环境,第一步就是在我那刚装的Win10 系统上安装jdk,过程并不顺利,由于之前都是用的win7,几乎都 ...

  6. 怎样将Excel包含某字符的单元格填充颜色

    在处理数据的时候,xmyanke想将Excel中包含某字符的单元格填充蓝色,比较容易看清,弄了好一阵子都没完成,最后试用条件格式处理了一下,终于实现了. 比如要将A1到A12区间包含数字1的单元格填充 ...

  7. php RFC兼容的电子邮件地址验证

    php中,进行RFC兼容的电子邮件地址验证的方法,有需要的朋友参考下吧. 分享一个可以验证RFC兼容的电子邮件地址的代码,支持RFC1123,2396,3696,4291,4343,5321等的验证. ...

  8. Linux常用命令(更新)

  9. ServiceModel 元数据实用工具 (Svcutil.exe)

    ServiceModel 元数据实用工具用于依据元数据文档生成服务模型代码,以及依据服务模型代码生成元数据文档 一.SvcUtil.exe ServiceModel 元数据实用工具可在 Windows ...

  10. 如何修改element.style样式

    相信很多朋友在修改主题css时遇到过一些问题,比如说出现这个elememt.style,这个有时候无法直接修改,因为找不到.因此可以通过css中的 !important 语法优先权来实现我们想要的效果 ...