Scala 中方法扩展实践

前言

这个名字不知道取得是否合适,简单来讲要干的事情就是给某个类型添加一些扩展方法,此场景在各类语言中都会用到,好比 C# 语言,若是咱们使用一个别人写好的类库,而又想给某个类库添加一些本身封装的方法,最好的方式就是使用扩展方法,具体实现方式此处不赘述。scala

起初,我觉得在 Scala 中也是这样使用的,可是直到今天我才恍然大悟,在 Scala 中扩展方法其实不是那么简单,此处说的不简单主要说的是实现的意义不简单,而不是实现方法。本文对此进行简单介绍。code

1、 实现方法

首先,来讲明实现方法,正如上文所说,在 Scala 中其实实现起来也很容易。对象

首先咱们有一个要扩展的类型假定为 C,定义以下:继承

trait A {
  def play = println("play")
}

就是这么简单的一个类,包含一个 play 方法,固然能够有各类各样的子类继承于他,及包含其余方法。ci

第二步,定义一个扩展方法的类型:it

trait BB[+T] {
  def self: T
}

此类用于包装咱们的被扩展类型,其中 self 就是一个要扩展类型的实例。(此处名字取 BB 实非本意,不知是 scala bug 仍是其余问题,若是此处只使用 B 来命名,下面会报错,有知情者烦请指点一二。)class

第三步,定义一个 trait 继承自 BB:扩展

trait C extends BB[A] {
  def draw = self.play
}

此类型里能够定义一系列的方法,这些方法就是即将被扩展的方法,咱们能够直接使用 self 来表示被扩展的对象实例,能够直接调用他的方法。coding

第四步,实现一个隐式类型,将 A 对象隐式转换为 C:bug

implicit class D(val self: A) extends C

最终,咱们能够直接对 A 对象的实例调用扩展方法:

new A {}.draw

2、分析

思路缜密,逻辑清晰((*^_^*)),实现起来很容易。开始的时候我觉得就是这样,因此为每一个类型写了一堆的扩展方法,自我感受良好,调用起来很方便。

可是这个地方有个问题,既然咱们本身定义了类型A,为何不直接将 draw 方法也写到这里面呢,瞎折腾啥,我以前是这么想的,也是这么用的。然而,今天我忽然意识到一个问题,在我使用的一个类库中,不少本身定义的类型也采用此种方式定义了大量的扩展方法,那我就纳闷了,为何不直接写到类型的定义中呢?

沉思半天,我恍然大悟,这是一种良好的封装方法。简单说来就是 A 这个类型可能包含了大量的不一样种类的方法,好比对于地理信息系统来讲,一个瓦片能够包含投影、裁剪、切割等多种种类的方法,每一个种类可能包含了一系列方法,因此采用这种方式的好处就是能够将这些不一样种类的方法放到不一样的扩展类型中进行管理,实现良好的封装。而且在后续调用中,无需判断此对象是不是 A 对象,只要判断此对象是不是 C 对象便可直接调用 C 中的方法,这样就对功能实现了良好的划分。

3、结束

看似一个简单的扩展方法,也有如此多的深层次逻辑,仍是须要学会思考、深刻的思考,这样才能发现更多 coding 中美的地方。

相关文章
相关标签/搜索