用老师和学生的例子比喻Actor编程模型
多个学生问多个老师问题
学生和老师都是Actor的作用就是收发消息,处理逻辑的
教学总监和班主任是ActorSystrm,是用来创建Actor的,并且监控和管理他创建的Actor
ActorSystrm是单例的,一个进程只要有一个即可
Actor是多例的,可以创建多个实例
Actor编程模式就通过送消息来实现并发的
Akka就是基于Actor编程模型实现的,可以是单机的也可以是分布式的
RPC通讯案例过程分析
大哥在机器一上有一个进程Master这个以后要进行通信的所里里面还有一个ActorSystem只能有一个,然后这个里面就可以有多个Actor,这个机器一有又很多的小弟机器二,三,等等等.小弟机器上就有Worker,里面也有ActorSystem只能有一个和可以有多个的Actor,他是用来管理这个机器上资源信息的
- 启动Master,然后内部会启动一个定时器,定期检测超时的worker,移除超时的Worker
- 启动Worker,跟Master建立网络链接,将自己的信息(id,内存,cou等信息)注册给Master
- Master接受到消息后会将Worker的信息保存起来,保存到内存,也可以持久化到磁盘,然后向Worker发送注册成功的消息
- Worker接受到了Master发送注册成功的消息,然后启动一个定时器,定期向Master’发送心跳(发送心跳的目的是为了报活)
- 实现的方式:AKKA,发送Case Class,为什么是CaseClass嫩因为他可以封装数据和进行模式匹配
写代码过程实现RPC框架
- 创建一个Master类继承Actor然后就会提示实现一个receive的 抽象方法这个方法是用来接受消息的
- 有Actor那就必须有ActorSystem所以就在下面创建半生类写个main方法创建ActorSystem
- 这个ActorSystem里要有两个参数,第一个是他的名字字符串随便写,第二个是config
- 但是config没有就要val一个config,他有一个叫ConfigFactory的工厂点一个Parse String传字符串的方法(里面传一个字符串可以起名叫ConfigStr)
- 但是又没有这个ConfigStr这个字符串,所以在上面val创建一个configStr字符串这个 字符就复制把
- 字符串里有两个参数可以先写死一个host是名字val一个"localhost",port是端口号val一个8888
- 使用ActorSystem创建Actor点一个actorOf方法里面有俩参数一个是类型Props[Master]泛型里面写继承的Actor的类名,第二个写字符串名字,随便起一个叫"MasterActor"
- 然后就可以发消息了先自己给自己发消息用创建的Actor的变量名加! 加想发的东西
- 最后在上面用receive方法接受,可以用模式匹配
------------------------------------接下来写Worker-----------------------------------------------
跟写Master一样改一下端口号
在reserve上面重写preStart方法这个会在构造方法之后reserve之前一定会执行一次,在这个方法里面就可以和Master建立链接
柯里化
空格下划线
def m(x: Int): Int = {x * x} m方法
val f = (a: Int) => a * a f函数
val arr = Array(1,2,3,4,5,6,7,8,9)
val arr1: Array[Int] = arr.map(f)
val arr2: Array[Int] = arr.map(m _)
分别调用了方法m,和函数f虽然说结果是一样的其实过程有很大的不同
map里是不能用方法的所以用的m方法是用空格下划线生成了一个新的函数,并且空格下划线 _可以省略
正常写法def m(x:Int , y:Int) : Int = x + y
柯里化写法def m(x:Int) (y:Int) : Int =x + y
柯里化通常是和隐式参数,隐式转换结合起来使用实现更加高级的功能
隐式参数 implicit
def m2(x: Int, y: Int = 20): Int = x + y
val r = m2(10)
普通方法可以在参数列表中指定默认值,一个是最后一个参数,也可以每个参数都指定默认值
def m1(x: Int)(y: Int = 100): Int = x + y
val r = m1(5)()
柯里化方法后面的括号传入的默认值,调用时也要指定多个括号,有默认值的括号没有不传参数
def m3(x: Int = 5)(y: Int = 100): Int = x + y
val r1 = m3()()
如果是两个默认参数就写两个空括号,如果有默认值还向传参也可以
def m1(x:Int=10)(implicit y:Int=100)=x+y
val o=m1(10)
如果在方法默认值上加上implicit就可以少写一个括号了
def m1(x:Int=10)(implicit y:Int=100)=x+y
val o=m1(10)
implicit val b=10
如郭在方法外面定义一个同类型的隐式参数就可以传到方法内取代原来的隐式参数
//隐式参数:编译时会到程序的上下文找与自己类型一样,不在乎参数名是否一致,有就传入,覆盖默认值
object MyContextObj {
implicit val ttt = 12345
}这边是封装了一个类写隐式参数
import myContextClass.ttt 可以以import导报的形式导到当前类下
import myContextClass._ 如果这个类里有很多不同类型的隐式参数海可以下划线全导过来
如果隐射式参数、方法定义在class中,先要创建这个类的实例,在用实例名称调用
val myContextClass = new MyContextClass
import myContextClass._
scala的泛型
class Pair[T <: Comparable[T]] {
def bigger(first:T , second:T): T={
if(first.compareTo(second) > 0) first else second
}
}
object Pair{
def main(args: Array[String]): Unit = {
val p=new Pair[Integer]
val r=p.bigger(5,10)
println(r)
}
}
这个是比较大小但是没有比较大小的方法就在Pair类中定义了一个方法new一个Pair对象泛型是Integer,
为什么不是Int类型嫩,因为Pair类中要定义泛型写了一个上界就必须是Comparable的子类孙子类什么的,但是
Int和Conmarable没关系只有Ingeger才是Comparable的子类,为什么要是Comparable的上界而不是别的人
的上界嫩因为要用他下面comparaTo的比较大小的方法,然后比较就是俩相减大于0就first大就返回first,
小于0就返回second,就实现了比较大小
RichFile案例
package cn.doit.com.day05.demo3
import scala.runtime.RichInt
object ToDemo {
def main(args: Array[String]): Unit = {
//Int 没有定义to方法,父类也没定义
//使用了隐式转化,使用RichInt中的To方法
1 to 10
//不使用隐式转换,显示的包装,要多敲好多次键盘
val r: Range.Inclusive = new RichInt(1) to (10)
//隐式转换, 隐式转换本质就是装饰(包装),背地里帮你包的
//scala默认就导入一些包 类 object. 隐式参数 方法 函数
// 1) import java.lang._ (117 types, 123 terms)
// 2) import scala._ (178 types, 172 terms)
// 3) import scala.Predef._ (123 terms, 62 are implicit)
//在 scala.LowPriorityImplicits 中有一个用import修饰的方法
//implicit def intWrapper(x:Int) =new runtime.RichInt(x)
//将Int 转成了 RichInt, 而RichInt中恰好定义了to方法
}
}
package cn.doit.com.day05.demo3
import java.io.File
import scala.io.Source
class RichFile(val file: File) {
def read(): String = {
//从文件中一次全部读取出来
Source.fromFile(file).mkString
}
}
object RichFile {
def main(args: Array[String]): Unit = {
val file = new File("D:\\a.txt")
// val content = file.read()
// val richFile = new RichFile(file)
// val content = richFile.read()
import MyPreDef._
val content = file.read()
println(content)
}
}
package cn.doit.com.day05.demo3
import java.io.File
object MyPreDef {
//隐式方法
implicit def fileToRichFile(file:File) = {
println("implicit method invoked")
new RichFile(file)
}
//隐式函数 隐式转换优先调用函数
implicit val file2RichFile = (file: File) => {
println("implicit func invoked")
new RichFile(file)
}
}
scala的泛型
package cn.doit.com.day05.demo04
/*
* [T <: Comparable[T]] 上界 upper bound java: <T extends Comparable>
* [T >: Comparable[T]] 下界 lower bound java: <T super Comparable>
* [T <% Comparable] 视图界定 view bound java: <T super Comparable>
* [T : Comparable] 上下文界定 context bound
* [-T] 逆变 方法输入参数
* [+T] 协变 方法返回
* */
class Pair[T <% Comparable[T]] {
def bigger(first:T, second: T): T ={
if (first.compareTo(second) > 0) first else second
}
}
object Pair {
def main(args: Array[String]): Unit = {
//Integer实现了Comparable接口
// val p = new Pair[Integer]
// val r = p.bigger(5, 10)
// println(r)
//如果使用T <% Comparable[T] 即视图界定,既不会报错,因为视图界定就是为了实现隐式转换的
//在Predef中有一个隐式转换方法 implicit def int2Integer(x: Int): java.lang.Integer = x.asInstanceOf[java.lang.Character]
val p2 = new Pair[Int]
//用implicit修饰的一个方法或函数 Int => Integer
//Int => Integer
val r2 = p2.bigger(5,10)
println(r2)
}
}
Ordering和Ordered 比较
Ordered 是对java 中comparable的一个扩展 , 又更加灵活的方法
Ordering 继承了compaartor 对compare方法进行了扩展
视图界定
<% 视图界定( view bound) 必须传一个隐式方法或函数
视图界定就是为了实现隐式转换 , 寻找对应的隐式转换方法
package cn.doit.com.day05.demo05
//Ordered中有 > < <= >= 等方法
//结论: 视图界定就是用来实现隐式转换的,需要一个隐式转换方法或函数
class MrRight[T <% Ordered[T]] {
def fanpaizi(first:T,second:T): T = {
if (first > second) first else second
}
}
object MrRight {
def main(args: Array[String]): Unit = {
import MyPreDef._
val mr = new MrRight[Boy]
val b1 = new Boy("zss",99)
val b2 = new Boy("lss",98)
val boy = mr.fanpaizi(b1, b2)
println(boy)
}
}
package cn.doit.com.day05.demo05
class Boy(val name:String, val fv:Int) /*extends Ordered[Boy]*/{
override def toString: String = s"Boy($name, $fv)"
/*override def compare(that: Boy): Int = {
this.fv - that.fv
}
*/
}
package cn.doit.com.day05.demo05
object MyPreDef {
//方法
implicit def boyToOrderedBoy(boy: Boy): Ordered[Boy] = new Ordered[Boy] {
override def compare(that: Boy): Int = {
println("implicit method invoked")
boy.fv - that.fv
}
}
//函数 函数优先级高
implicit val boy2ToOrderedBoy = (boy: Boy) => new Ordered[Boy] {
override def compare(that: Boy): Int = {
println("implicit func invoked")
boy.fv - that.fv
}
}
}
上下文界定
: 必须传一个隐式类型的参数
package cn.doit.com.day05.demo05
//上下文界定也是用来实现隐式转换的,但是必须有一个隐式转换的类型参数
class MissRight[T : Ordering] {
def choose(first:T , second:T):T = {
//把 T:Ordering 转化成了 Ordering[T]类型的
val ord: Ordering[T] = implicitly[Ordering[T]]
// gteq: x - y >= 0
if (ord.gteq(first,second)) first else second
}
}
object MissRight {
def main(args: Array[String]): Unit = {
import MyPreDef.OrderingGirl
val missr: MissRight[Girl] = new MissRight[Girl]
val g1 = new Girl("金莲",38)
val g2 = new Girl("吉泽老师",40)
val girl = missr.choose(g1, g2)
println(girl)
}
}
package cn.doit.com.day05.demo05
class Girl(val name:String , val fv:Double) {
//重写toString
override def toString = s"Girl($name, $fv)"
}
package cn.doit.com.day05.demo05
object MyPreDef {
//既不是方法也不是函数,是一个隐式的object
implicit object OrderingGirl extends Ordering[Girl] {
override def compare(x: Girl, y: Girl): Int = {
//Double实现了comparable接口
java.lang.Double.compare(x.fv , y.fv)
}
}
}
柯里化结合隐式
使用柯里化+隐式转换方法/函数 实现类似视图界定
使用柯里化+隐式参数 实现上下文界定
package cn.doit.com.day05.demo06
import cn.doit.com.day05.demo05.{Girl, MissRight, MyPreDef}
class Pair[T] {
//柯里化方法结合隐式转换方法或者函数 可以实现数图界定的功能
def select(first:T , second:T)(implicit f:T => Ordered[T]) = {
if(first > second) first else second
}
//柯里化方法结合隐式类型参数 可以实现上下文界定的功能
def choose(first:T , second:T)(implicit ord: Ordering[T]): T = {
if (ord.gteq(first,second)) first else second
}
}
object Pair {
def main(args: Array[String]): Unit = {
val pair = new Pair[Boy]
val a1 = new Boy("zss",18)
val a2 = new Boy("lss",28)
//使用柯里化+隐式转换方法或函数就可以实现类似视图界定的功能
import MyPreDef._
val boy = pair.select(a1, a2)
println(boy)
val pair2: Pair[Girl] = new Pair[Girl]
val g1 = new Girl("金莲",38)
val g2 = new Girl("吉泽老师",40)
import MyPreDef.OrderingGirl
val girl = pair2.choose(g1,g2)
println(girl)
}
}
package cn.doit.com.day05.demo06
import cn.doit.com.day05.demo05.Girl
object MyPreDef {
implicit def boyToOrderedBoy(boy: Boy): Ordered[Boy] = new Ordered[Boy] {
override def compare(that: Boy): Int = {
println("implicit method invoked")
boy.fv - that.fv
}
}
implicit val boy2ToOrderedBoy = (boy: Boy) => new Ordered[Boy] {
override def compare(that: Boy): Int = {
println("implicit func invoked")
boy.fv - that.fv
}
}
//既不是方法也不是函数,是一个隐式的object
implicit object OrderingGirl extends Ordering[Girl] {
override def compare(x: Girl, y: Girl): Int = {
//Double实现了comparable接口
java.lang.Double.compare(x.fv , y.fv)
}
}
}
package cn.doit.com.day05.demo06
class Boy(val name:String, val fv:Int){
override def toString: String = s"Boy($name, $fv)"
}
隐式转换就是想要对方法进行增强,对类进行增强或者扩展, 有两种方式
第一种是 对类进行包装,使用柯里化方法和隐式函数/方法来其进行增强 相当于视图界定
第二种 就是继承, 定义一个隐式的object继承某个类型也可以对其进行增强 相当于上下文界定
在java中扩展方法 :
1. 继承 继承后可以在子类中加方法,可以也重写方法来增强方法
2. 包装
3. 动态代理