职责链模式

责任链模式在面向对象程式设计里是一种软件设计模式,它包含了一些命令对象和一系列的处理对象。每一个处理对象决定它能处理哪些命令对象,它也知道如何将它不能处理的命令对象传递给该链中的下一个处理对象。该模式还描述了往该处理链的末尾添加新的处理对象的方法。

以上是wiki对职责链模式的定义。

举个例子来说,我们的系统中需要记录日志的功能。日志需要根据优先级被发送到不同的地方。

低优先级的日志输出到命令行就好了。而高优先级的错误信息则需要通过邮件通知相关人员并且输出到命令行。

这个例子也是来自wiki的。

阅读全文 »

策略模式

策略模式作为一种软件设计模式,指对象有某个行为,但是在不同的场景中,该行为有不同的实现算法。

以上是中文wiki中对策略模式的定义。

In computer programming, the strategy pattern (also known as the policy pattern) is a software design pattern that enables an algorithm’s behavior to be selected at runtime. The strategy pattern:

  • defines a family of algorithms,
  • encapsulates each algorithm, and
  • makes the algorithms interchangeable within that family.

Strategy lets the algorithm vary independently from clients that use it.

阅读全文 »

声明

这系列博文的目标读者仅限于报名参加了这门课并且看完了视频,看完了作业的instruction之后仍有困难的同学。

这系列博文不会公布作业的答案,那是违反Coursera的code of honor的。

我只会试着解释作业中已有的代码,以及应该如何入手。

其实,写这个系列博文对我的帮助比对读者的帮助要大。

这周的作业不太难,主要就是一个观察者模式。

阅读全文 »

#前尘
Principles of Reactive Programming在4月13号又开课了。
https://www.coursera.org/course/reactive

上次开课是在2013年的11月,当时我刚第一次上完Functional programming principles in Scala,热情很高于是就报名参加了这门课。
还群发了一个邮件找人一起上课。

但是上了几周发现有点难,于是就放弃了。现在去bitbucket看,最后一次push停留在了2013-11-18。

后来还在上海被8x鄙视于无形之中。

后世

14年做了几个月的Scala开发,后来Functional programming principles in Scala再次开课又上了一遍,拿了个认证证书。

阅读全文 »

源起

前两天,在一个武汉本地程序员聚集的技术社区微信群里某位群友发了两张图片:

这是某个IT公司的招聘宣传,为程序员提供的鼓励师。

(由于图片出现在愚人节期间,不确定该公司是真的有这样的人员配备,还是恶作剧的,此处暂且存疑)

阅读全文 »

时间是以何种方式流逝的呢?

三个月瞬间就不见了。

对照着去年的总结和当时对未来的期望写一下2015年第一季度吧。

博客

惨不忍睹。

除了一个应付任务的tech radar的session写在了博客上,其他啥都没写。

阅读全文 »

2014年即将结束,需要做一些总结。

既然总结是写在博客上的,第一项就先说博客吧。

博客

2014年写了18篇博客,其中15篇和Scala有关,自认为都是有且仅有干货的。

对此,我比较_满意_。

不过这个数字存在欺骗性,15篇Scala的博客,其中4篇写于1月份,6篇写于6月份,其余的零散的写就与其他月份。

阅读全文 »

大家都知道Scala标准库的List有一个用来做聚合操作的foldLeft方法。

比如我定义一个公司类:

1
case class Company(name:String, children:Seq[Company]=Nil)

它有名字和子公司。
然后定义几个公司:

1
val companies = List(Company("B"),Company("A"),Company("T"))

三家大公司,然后呢,我假设有一家超牛逼的公司把它们给合并了:

阅读全文 »

假设一个场景

需要在50个随机数中找到前两个可以被3整除的数字。

听起来很简单,我们可以这样来写:

1
2
3
4
5
6
7
8
9
def randomList = (1 to 50).map(_ => Random.nextInt(100)).toList

def isDivisibleBy3(n: Int) = {
val isDivisible = n % 3 == 0
println(s"$n $isDivisible")
isDivisible
}

randomList.filter(isDivisibleBy3).take(2)

一个产生50个随机数的函数;

一个检查某数字是否能被3整除的函数;

阅读全文 »

Scala里的for关键字是个很有趣的东西。可以用来把多层嵌套for循环写成一层。比如这样:

1
for(i<-1 to 10;j<-1 to 10;k<-1 to 10) yield(s"$i $j $k")

这行代码执行的结果是这样的:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
1 1 1
1 1 2
1 1 3
1 1 4
1 1 5
1 1 6
1 1 7
1 1 8
1 1 9
1 1 10
1 2 1
1 2 2
1 2 3
1 2 4
1 2 5
1 2 6
1 2 7
1 2 8
1 2 9
1 2 10
......
......

这样,就可以用一行代码写出三层循环的效果。代码看起来非常紧凑,噪音很少。

但是今天主要要说的不是这种for,而是它和Option结合的写法。

阅读全文 »

我所在的项目在用Scala + Play framework做一个web app。

Play自带的evolutions是一个DB Migration工具,从一开始我们就在用它来做所有阶段的数据迁移工作。

运行自动化测试时它可以帮每个测试用例在H2中创建数据(H2是Play默认的内存数据库)。
在下一个测试用例运行时evolutions则会创建一份和上次完全相同的新数据,这样我们的测试可以获得独立性而不用担心之前的测试遗留的副作用。也不用担心会给下一个测试遗留下什么脏数据。

在测试或者部署环境中运行时它也可以针对Postgres做数据迁移。

这一切看起来都挺好,我们就差喊evolutions是我们忠实的好伙伴了。

但是,快到给终端客户部署时,某一家客户提出他们一定要使用SQL Server,我们最初提出的使用Postgres他们不接受了。这时我们才发现evolutions的设计初衷就是在开发和测试阶段提供便利性,它根本就没想成为一个production ready的东西。

阅读全文 »

最近还是在看郑大翻译的《Scala程序设计》,其中第十一章还有一句话:

如果trait有方法实现,那么Java类就不能实现这个trait

口说还是无凭,还是拍照为证:

我感觉这句话是错的,下面寻根究底地探索一下。

trait这个语言特性前面的博文讲过。

阅读全文 »

最近在看郑大翻译的《Scala程序设计》,其中第十一章有一句话:

如果Scala类有方法接收闭包,这些方法在Java里就不可用,因为Java目前尚不支持闭包。

口说无凭,拍照为证:

当时看到这句话就感觉不对。因为JVM本身没有对函数式编程提供任何支持,所以无论是Java中常用的Guava,还是Scala,其对闭包的支持都是通过用类来包裹函数实现的。

如果说Java目前(其时Java 8还没面世)尚不支持闭包,那倒是还说得过去,因为毕竟是要用类包裹一层,不算真正的函数传递。

阅读全文 »

我所在的项目的技术栈选用的是Play framework做后端API,前端用Angular JS。

因为用了Scala和Play,构建工具很自然用的就是sbt。

而由于前端用了Angular,所以functional test就选用了和Angular结合较好的protractor。

这一切看起来似乎很美好,一个无状态的后端,一个数据和UI双向绑定的前端。What could possibly go wrong?

一开始也确实如此,没什么问题。我们为了让functional test在CI上跑起来,写了一个脚本来把play dist打出的包部署到CI所在机器上,然后运行protractor。

这个脚本运行还算ok,偶尔有点小问题,修一修也就好了。

阅读全文 »

Lower bound,不知道这个词的确切中文翻译是怎样的。我们直接看例子吧。

1
2
3
class Pair[T](val first: T, val second: T) {
def replaceFirst[R >: T](newFirst: R): Pair[R] = new Pair[R](newFirst, second)
}

我们定义一个叫做Pair的类,其中可以包含两个元素,元素类型为泛型的T。

Pair类中有一个replaceFirst方法,用来把第二个元素和一个新的元素结合起来组成一个新的Pair。新的元素的类型是泛型的R。新组成的Pair的类型是Pair[R]。

到这里我们就要想了,一个T和一个R,它们俩怎么组成新的Pair呢?新的Pair的类型怎么能是Pair[R]呢?

replaceFirst的签名给我们说明了这一点。[R >: T]。这种标记的含义是说R是T的基类。那么一个T和一个R自然可以组合成一个R的Pair了。

阅读全文 »

实在想不到什么动词可以当做脱衣服来讲了,所以从现在开始这系列博文就叫做Desugar Scala了。除非哪天才思泉涌,又想到了新词:)

开始正文。

名字叫做unapply和unapplySeq的方法在Scala里也是有特殊含义的。

我们前面说过case class在做pattern match时很好用,而除case class之外,有unapply或unapplySeq方法的对象在pattern match时也有很好的应用场景。

比如这段代码:

1
2
3
object Square {
def unapply(z: Double): Option[Double] = Some(math.sqrt(z))
}
阅读全文 »

在Scala中,名字叫做update的方法是有特殊作用的。

比如:

1
2
3
val scores = new scala.collection.mutable.HashMap[String, Int]
scores("Bob") = 100
val bobsScore = scores("Bob")

以上三行代码,我们创建了一个可变的map来存储得分情况,然后我们记录了Bob的得分是100分,最后我们又把Bob的分数取出来了。

这三行代码看似平淡无奇,实则暗藏了一点点玄机。

第二行实际是调用了HashMap的update方法。

阅读全文 »

好久没有写博客了,上一次更新竟然是一月份。

说工作忙都是借口,咋有空看美剧呢。

这半年荒废掉博客说到底就是懒,惯性的懒惰。写博客这事儿,一丢掉就很久捡不起来。

闲话到此为止,下面进入正题。

Default parameter value,默认参数值。
这个很容易理解,给参数一个默认值,如果调用者不显式指明参数值,则使用默认值。如果显式指明了,那就用显式指明的值。

举个例子:

阅读全文 »

上次博客谈到了implicit function,但是漏掉了一些东西,今天补上。

由于上次已经讲过implicit function的实现细节,这次就不再重复了。今天只补充上次漏掉了的implicit function的一种很好的实践。

先看一段specs2的测试代码:

1
2
3
4
5
6
7
8
9
10
11
import org.specs2.mutable._

class HelloWorldSpec extends Specification {

"The 'Hello world' string" should {

"contain 11 characters" in {
"Hello world" must have size 11
}
}
}

我们试着理解这个测试代码在做什么的时候,无须多少思考,因为它和人类语言一样的亲近和自然。但是如果我们想知道specs2如何做到这一点时,就有点费解了。

我们知道xObject yMethod zParameter的写法是一个语法糖,它和xObject.yMethod(zParameter)是一样的。也就是说should和in都是方法名。于是,问题来了,should和in前面是个String啊,String上哪有这两个方法的定义?

阅读全文 »