FunDA(10)- 用户功能函数模式:User Function Model
前面我们提过:FunDA就像一个管道(PipeLine)。管道内流动着一串数据(Data)或者运算指令(Action)。管道的源头就是能产生纯数据的数据源(Source),跟着在管道的中间会有一些节点(WorkNode),我们可以在这些节点施用(apply)用户提供的功能函数(Task)。用户功能函数可以截取并使用管道中流动的数据或者指令,然后利用一种水龙头开关机制(Valve)来影响流动元素:可以截住、直接传送、传送修改版本、插入新数据。作为FunDA的用户,需要掌握用户功能函数编写模式。我们先从一个简单的用户函数开始介绍:
//定义一个用户作业函数:列印数据,完全不影响数据流
def printAlbums: FDATask[FDAROW] = row => {
row match {
case album: Album =>
println("____________________")
println(s"品名:${album.title}")
println(s"演唱:${album.artist}")
println(s"年份:${album.year}")
println(s"发行:${album.publisher}")
//原封不动直接传下去
fda_next(album)
case r@ _ => fda_next(r)
}
}
上面这个用户函数的类型是FDATask[FDAROW],这是一个函数类型:
//作业类型
type FDATask[ROW] = ROW => Option[List[ROW]]
所以我们用lambda来代表函数内容:row => {函数功能}。lambda为用户函数提供了当前元素。我们用下面方式调用这个用户函数:
val streamLoader = FDAStreamLoader(slick.driver.H2Driver, toTypedRow _)
val albumStream = streamLoader.fda_typedStream(albumsInfo.result)(db)(.minutes, , )()()
//定义一个用户作业函数:列印数据,完全不影响数据流
def printAlbums: FDATask[FDAROW] = row => {
row match {
case album: Album =>
println("____________________")
println(s"品名:${album.title}")
println(s"演唱:${album.artist}")
println(s"年份:${album.year}")
println(s"发行:${album.publisher}")
//原封不动直接传下去
fda_next(album)
case r@ _ => fda_next(r)
}
} albumStream.appendTask(printAlbums).startRun
我们把用户函数printAlbums传入appendTask来对数据流进行施用。我们可以在appendTask后面再接一个用户函数,这个用户函数截取到的数据流元素是原装的数据源,因为在任何情况下printAlbums都会原封不动地把截获的元素用fda_next()传下去。运行一下下面这个就清楚了:
albumStream.appendTask(printAlbums).appendTask(printAlbums).startRun
相反情况我们只需要做下面的修改把fda_next替换成fda_skip就可以证实了:
//原封不动直接传下去
fda_skip
// fda_next(album)
我们也可以根据当前元素情况生成一条FDAActionROW,它的定义是这样的:
type FDAAction = DBIO[Int] case class FDAActionRow(action: FDAAction) extends FDAROW
def fda_mkActionRow(action: FDAAction): FDAActionRow = FDAActionRow(action) class FDAActionRunner(slickProfile: JdbcProfile) { import slickProfile.api._ def fda_execAction(action: FDAAction)(slickDB: Database): Int =
Await.result(slickDB.run(action), Duration.Inf)
}
object FDAActionRunner {
def apply(slickProfile: JdbcProfile): FDAActionRunner = new FDAActionRunner(slickProfile)
}
我们可以把一条FDAActionRow传下去:
def updateYear: FDATask[FDAROW] = row => {
row match {
case album: Album => {
val updateAction = albums.filter(r => r.title === album.title)
.map(_.year)
.update(Some())
fda_next(FDAActionRow(updateAction))
}
case others@ _ => fda_next(others)
}
}
我们也可以把原数据同时传下去:
def updateYear: FDATask[FDAROW] = row => {
row match {
case album: Album => {
val updateAction = albums.filter(r => r.title === album.title)
.map(_.year)
.update(Some())
fda_next(FDAActionRow(updateAction))
fda_next(album)
}
case others@ _ => fda_next(others)
}
}
我们需要FDAActionRunner来运算action:
val runner = FDAActionRunner(slick.driver.H2Driver)
def runActions: FDATask[FDAROW] = row => {
row match {
case FDAActionRow(action) =>
runner.fda_execAction(action)(db)
fda_skip
case others@ _ => fda_next(others)
}
}
现在试试运转这个管道:
albumStream.appendTask(updateYear).appendTask(runActions).appendTask(printAlbums).startRun
实际上updateYear和runActions可以一步完成。但细化拆分功能就是函数式编程的一个特点,因为能够更自由的进行组合,这其中就包括了并行运算组合。
下面是这篇讨论的示范源代码:
package com.bayakala.funda.fdasources.examples
import slick.driver.H2Driver.api._
import com.bayakala.funda.fdasources.FDADataStream._
import com.bayakala.funda.samples._
import com.bayakala.funda.fdarows._
import com.bayakala.funda.fdapipes._
import FDAValves._
import com.bayakala.funda.fdarows.FDARowTypes._
import scala.concurrent.duration._ object Example2 extends App {
val albums = SlickModels.albums
val companies = SlickModels.companies //数据源query
val albumsInfo = for {
(a,c) <- albums join companies on (_.company === _.id)
} yield (a.title,a.artist,a.year,c.name) //query结果强类型(用户提供)
case class Album(title: String, artist: String, year: Int, publisher: String) extends FDAROW
//转换函数(用户提供)
def toTypedRow(row: (String, String, Option[Int], String)): Album =
Album(row._1, row._2, row._3.getOrElse(), row._4) val db = Database.forConfig("h2db") val streamLoader = FDAStreamLoader(slick.driver.H2Driver, toTypedRow _)
val albumStream = streamLoader.fda_typedStream(albumsInfo.result)(db)(.minutes, , )()()
//定义一个用户作业函数:列印数据,完全不影响数据流
def printAlbums: FDATask[FDAROW] = row => {
row match {
case album: Album =>
println("____________________")
println(s"品名:${album.title}")
println(s"演唱:${album.artist}")
println(s"年份:${album.year}")
println(s"发行:${album.publisher}")
//原封不动直接传下去
// fda_skip
fda_next(album)
case r@ _ => fda_next(r)
}
} // albumStream.appendTask(printAlbums).appendTask(printAlbums).startRun def updateYear: FDATask[FDAROW] = row => {
row match {
case album: Album => {
val updateAction = albums.filter(r => r.title === album.title)
.map(_.year)
.update(Some())
fda_next(FDAActionRow(updateAction))
fda_next(album)
}
case others@ _ => fda_next(others)
}
}
val runner = FDAActionRunner(slick.driver.H2Driver)
def runActions: FDATask[FDAROW] = row => {
row match {
case FDAActionRow(action) =>
runner.fda_execAction(action)(db)
fda_skip
case others@ _ => fda_next(others)
}
} albumStream.appendTask(updateYear).appendTask(runActions).appendTask(printAlbums).startRun }
FunDA(10)- 用户功能函数模式:User Function Model的更多相关文章
- thinkphp 的两种建构模式 第一种一个单入口里面定义两个模块,前台和后台,函数控制模块必须function.php前台加载前台模块的汉书配置文件,后台加载后台模块的汉书配置文件,公共文件共用。第二种架构模式两个单入口文件,分别生成两个应用定义define。。。函数可以定义配置文件。。。。
thinkphp 的两种建构模式 第一种一个单入口里面定义两个模块,前台和后台,函数控制模块必须function.php前台加载前台模块的汉书配置文件,后台加载后台模块的汉书配置文件,公共文件共用. ...
- 详解JavaScript函数模式
JavaScript设计模式的作用是提高代码的重用性,可读性,使代码更容易的维护和扩展.在javascript中,函数是一类对象,这表示他可以作为参数传递给其他函数:此外,函数还可以提供作用域. 创建 ...
- 【翻译】Flink Table Api & SQL — 用户定义函数
本文翻译自官网:User-defined Functions https://ci.apache.org/projects/flink/flink-docs-release-1.9/dev/tabl ...
- MVC5 网站开发之七 用户功能 2 用户添加和浏览
目录 MVC5网站开发之一 总体概述 MVC5 网站开发之二 创建项目 MVC5 网站开发之三 数据存储层功能实现 MVC5 网站开发之四 业务逻辑层的架构和基本功能 MVC5 网站开发之五 展示层架 ...
- 应用C#和SQLCLR编写SQL Server用户定义函数
摘要: 文档阐述使用C#和SQLCLR为SQL Server编写用户定义函数,并演示用户定义函数在T-SQL中的应用.文档中实现的 Base64 编码解码函数和正则表达式函数属于标量值函数,字符串分割 ...
- ASP.NET MVC+EF框架+EasyUI实现权限管理系列(17)-注册用户功能的细节处理(各种验证)
原文:ASP.NET MVC+EF框架+EasyUI实现权限管理系列(17)-注册用户功能的细节处理(各种验证) ASP.NET MVC+EF框架+EasyUI实现权限管系列 (开篇) (1):框 ...
- Windows 10新功能
Windows 10 中面向开发人员的新增功能 Windows 10 及新增的开发人员工具将提供新通用 Windows 平台支持的工具.功能和体验.在 Windows 10 上安装完工具和 SDK后, ...
- php文字、图片水印功能函数封装
一直在做有关php文字图片上传方面的工作,所以把此功能函数整理了一次,现在分享给大家. <?php class image { var $g_img; var $g_w; var $g_h; v ...
- 使用"立即执行函数"(Immediately-Invoked Function Expression,IIFE)
一.原始写法 模块就是实现特定功能的一组方法. 只要把不同的函数(以及记录状态的变量)简单地放在一起,就算是一个模块. function m1(){ //... } function m2(){ // ...
随机推荐
- 讲真的,千万别得罪会PS的人
传说中有一种软件炒鸡可怕 那就是PS,专业术语是photoshop! 它能让你貌美如花 也能让你瞬间丑得掉渣 更可怕的是网络上大神的出现 简直让我们难以想象的厉害! 下面大家一起来欣赏一下 那些大神帮 ...
- [BAT] xcopy拷贝远程服务器共享文件到本地
net use * /del /yes NET USE Y: \\10.86.17.243\d$ Autotest123 /user:MSDOMAIN1\doautotester set source ...
- Fiddler的钩子hook导致电脑无法连上网络
今天,电脑怎么都无法连上网络,重启了几次电脑也不行,网络环境是没有问题的,后来同事告诉我,Fiddler有一个BUG,就是Fiddler获取钩子之后没有释放掉,必须启动Fiddler,再关闭Fiddl ...
- Telnet 安装
Telnet 安装 一.Telnet 安装 (1) 登录目标主机检测 telnet 服务是否正常 [root@localhost ~]# telnet localhost -bash: telnet: ...
- c++11多线程学习笔记之三 condition_variable使用
从windows角度来说,condition_variable类似event. 阻塞等待出发,不过condition_variable可以批量出发. 代码如下: // 1111111.cpp : 定义 ...
- hibernate4 , spring3 使用 org.springframework.orm.hibernate3.annotation.AnnotationSessionFactoryBean 报错 Implementing class
错误代码如下 Caused by: org.springframework.beans.factory.BeanCreationException: Error creating bean with ...
- 由已打开的文件读取数据---read
头文件:#include<unistd.h> 函数原型:ssize_t read(int fd,void *buf,size_t count); 参数说明:fd:文件描述符 buf:存放读 ...
- hdu-1175(bfs+剪枝)
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1175 思路:用bfs,注意要转弯的次数,次数大于两次就跳过. #include<iostream ...
- 马婕 2014MBA专硕考试 报刊选读 4 朝鲜战争会爆发吗?(转)
http://blog.sina.com.cn/s/blog_3e66af4601016ela.html War unlikely, but Koreans still on cliff edge 战 ...
- HDU 1716 排列2 (格式问题+排列)
题意:. 析:我们完全可以STL里面的函数next_permutation(),然后方便,又简单,这个题坑就是在格式上. 行末不能有空格,结尾不能有空行,不大好控制,必须控制好第一次数. 这个题本应该 ...