scala学习手记28 - Execute Around模式
我们访问资源需要关注对资源的锁定、对资源的申请和释放,还有考虑可能遇到的各种异常。这些事项本身与代码的逻辑操作无关,但我们不能遗漏。也就是说进入方法时获取资源,退出方法时释放资源。这种处理就进入了Execute Around模式的范畴。
在scala里可以用函数值实现这种模式。下面是一个示例,使用Resource类演示了事务的开启和释放:
class Resource private() {
println("Starting transaction...")
private def cleanUp() {
println("Ending transaction...")
}
def op1 = println("Operation 1")
def op2 = println("Operation 2")
def op3 = println("Operation 3")
}
object Resource {
def use(codeBlock: Resource => Unit) {
val resource = new Resource try {
codeBlock(resource)
} finally {
resource.cleanUp()
}
}
}
这段代码里将Resource类的构造器标记为private,这样就只能在Resource类内部和它的伴生类中创建实例了。因为只能在这两个地方创建实例,从而保证是可以按照确定的方式使用这个类的对象了,也就可以保证其行为是按照确定的方式执行。cleanUp()方法也被标记为private,确保不会被意外调用。第一行的print语句是具体事务操作的占位符。调用构造函数时,事务启动;调用cleanUp()函数时,事务终结。此外Resource类中还准备了一些实例方法,如op1()、op2()等。
在伴生对象里有一个默认public的方法use,它接收一个函数值作为参数。use()方法创建了一个Resource的实例,在try和finally块的保护之下,把这个实例传给了给定的函数值。在finally块里,调用了Resource私有实例方法cleanUp()。
看一下是如何使用Resource类的:
Resource.use { resource =>
resource.op1
resource.op2
resource.op3
resource.op1
}
代码输出结果是:

调用Resource的伴生对象时,会自动创建一个Resource实例,等到传递的函数值执行结束后,会自动调用cleanUp方法释放占用的资源。
上面模式的一个变体是Loan模式。如果想确保非内存资源得到确定性释放,就可以使用这个模式。可以这样认为这种资源密集型的对象是借给你的,用过之后应该立即归还。
下面是一个Loan模式的例子:
import java.io._
def writeToFile(fileName: String)(codeBlock: PrintWriter => Unit) = {
val writer = new PrintWriter(new File(fileName))
try {
codeBlock(writer)
} finally {
writer.close()
}
}
现在调用writeToFile()将一些内容写入文件:
writeToFile("output.txt") { writer => writer write "hello from Scala" }
方法的执行结果:

作为writeToFile()方法的使用者,我们不必操心文件的关闭。在代码块里,这个文件是借给我们用的。我们可以用得到的PrintWriter实例进行写操作,一旦从这个块返回,方法就会自动关闭文件。
###############
scala学习手记28 - Execute Around模式的更多相关文章
- scala学习手记40 - case表达式里的模式变量和常量
再来看一下之前的一段代码: def process(input: Any) { input match { case (a: Int, b: Int) => println("Proc ...
- scala学习手记23 - 函数值
scala的一个最主要的特性就是支持函数编程.函数是函数编程中的一等公民:函数可以作为参数传递给其他函数,可以作为其他函数的返回值,甚至可以在其它函数中嵌套.这些高阶函数称为函数值. 举一个简单的例子 ...
- scala学习手记40 - 使用case类
前面两节我们已经多次接触过case关键字了.case关键字不仅可以用在match/case中来执行模式匹配,也可以用来修饰类.不过用case修饰的类也主要是用来做模式匹配.在上一节曾经提到过match ...
- scala学习手记38 - 方法命名约定和for表达式
方法命名约定 之前在学习<运算符重载>一节时曾经说过一个方法命名约定:方法的第一个字符决定了方法的优先级.现在再说另一个命名约定:如果方法以冒号(:)结尾,则调用目标是运算符后面的实例. ...
- scala学习手记34 - trait方法的延迟绑定
trait的方法的延迟绑定就是先混入的trait的方法会后调用.这一点从上一节的实例中也可以看出来. 下面再来看一个类似的例子: abstract class Writer { def write(m ...
- scala学习手记17 - 容器和类型推断
关于scala的类型推断前面已经提到过多次.再来看一下下面这个例子: import java.util._ var list1: List[Int] = new ArrayList[Int] var ...
- scala学习手记8 - 自适应的默认做法
scala有一些默认做法,会让代码更简洁.更易读写,下面列出了这样几个特性: 1. 支持脚本.scala支持脚本,因此无须将所有的代码都放到类里.如果脚本可以满足需求,就将代码放到一个脚本里,无须再创 ...
- scala学习手记3 - var和val
scala中用var和val定义变量都是可以的. 用val定义的变量是不可变的,被初始化后值就固定下来,不可以再被修改(这类似于java中的final关键字):用var定义的变量是可变的,可以任意修改 ...
- Scala学习手记1 - 快速体验
又重新开始了scala的学习,因为中断了太长时间,所以这次还得从零开始.学习的过程就记录在这个博客上了. 这次学习的教程是<scala程序设计 java虚拟机多核编程实战>,我在多看上买了 ...
随机推荐
- Replay attack 回放攻击
w http://baike.baidu.com/item/重放攻击 重放攻击(Replay Attacks)又称重播攻击.回放攻击或新鲜性攻击(Freshness Attacks),是指攻击者发送一 ...
- js滚动显示: 滚动条置顶/底
<script> //当聊天室的内容超出页面范围时, 如何让页面刷新后 显示最下面的内容 document.getElementByIdx ( 'chatboard').scrollTop ...
- 转!!关于java类初始化顺序
原文地址:http://www.cnblogs.com/luckygxf/p/4796955.html 1.没有继承 静态变量->静态初始化块->变量->变量初始化块->构造方 ...
- Pandas 删除指定列中为NaN的行
定位要删除的行 需求:删除指定列中NaN所在行. 如下图,’open‘ 列中有一行为NaN,定位到它,然后删除. 定位: df[np.isnan(df['open'])].index # 这样即可定位 ...
- plotly简单绘制柱状图
代码: import plotly.offline as pltoff import plotly.graph_objs as go def bar_charts(name="bar_cha ...
- 自己定义图片的progressbar
版权声明:本文为博主原创文章,未经博主同意不得转载. https://blog.csdn.net/zpf8861/article/details/36183455 Android系统自带的Progre ...
- Android Studio 启动时不自动打开项目
主界面中,选择单击菜单栏 File ,单击 Settings 选择 Appearance & Behavior 选项.选择System Settings选项.取消勾选Reopen last p ...
- Hbase 学习笔记1----shell
Hbase 是一个分布式的.面向列的开源数据库,其实现是建立在google 的bigTable 理论之上,并基于hadoop HDFS文件系统. Hbase不同于一般的关系型数据库(RDBMS ...
- Delphi 正则表达式语法(4): 常用转义字符与 .
Delphi 正则表达式语法(4): 常用转义字符与 . // \d 匹配所有数字, 相当于 [0-9] var reg: TPerlRegEx; begin reg := TPerlRegE ...
- Spring框架学习之IOC(二)
Spring框架学习之IOC(二) 接着上一篇的内容,下面开始IOC基于注解装配相关的内容 在 classpath 中扫描组件 <context:component-scan> 特定组件包 ...