天天看点

Akka探索第二个例子by fsharp

本文重度借鉴了github上akkabootcamp教程。

先上代码

open Akka
open Akka.Actor
open System

type Message = 
    | ContinueProcess 
    | InputSuccess of string
    | InputError of string 
    | NullInput of string
    | ValidateError of string

type ConsoleWriteActor() =
    inherit UntypedActor()
    override x.OnReceive(message) = 
        let msg = message :?> Message 
        match msg with
        |ValidateError r -> printfn "%A" r
        |NullInput r -> printfn "%A" r
        |InputSuccess r -> printfn "%A" r 
        |_ -> printfn "%A" message

[<Literal>]
let ExitCommand = "exit"
[<Literal>]
let StartCommand = "start" 

type ValidateActor(consoleWriterActor: IActorRef) =
    inherit UntypedActor()
    let _consoleWriterActor = consoleWriterActor
    override x.OnReceive(message) = 
        let msg = message :?> string
        if(String.IsNullOrEmpty(msg)) then
            _consoleWriterActor.Tell(NullInput "no input receive")
        else
            if (msg.Length % 2 = 0) then
                _consoleWriterActor.Tell(InputSuccess "Thank you, message is Valid")
            else
                _consoleWriterActor.Tell(ValidateError "Invalid: Odd msg")
        //x.Sender.Tell(ContinueProcess) 1

type ConsoleReaderActor(validateActor:IActorRef) = 
    inherit UntypedActor()
    let _validateActor = validateActor
    override x.OnReceive(message) = 
        if(message.Equals(StartCommand)) then 
            printfn "Start now!"
        else 
            let uinput = message |> string //2
       //let uinput = Console.ReadLine()
            if((not <| String.IsNullOrEmpty(uinput)) && uinput = ExitCommand) then
                UntypedActor.Context.System.Terminate() |> ignore
            else  
                _validateActor.Tell(uinput)

let system = ActorSystem.Create "my-system"
let consoleWriteActor = system.ActorOf(Props.Create<ConsoleWriteActor>())
let validateActor = system.ActorOf(Props.Create<ValidateActor>(consoleWriteActor))
let consoleReadActor = system.ActorOf(Props.Create<ConsoleReaderActor>(validateActor))
consoleReadActor.Tell(StartCommand)
consoleReadActor.Tell("aa")
consoleReadActor.Tell("")
consoleReadActor.Tell("hello")
system.Terminate()      

这里代码做了这样几件事

1.从控制台获取用户输入

2.将用户输入进行验证

3.将验证后的数据根据类别进行输出

这里我们使用了ConsoleReaderActor,ValidateActor和ConsoleWriteActor来分别进行任务1-3的处理。因为三者之间仅通过Event进行通信,所以可以很好的解耦系统。不同的Actor也可以部署到不同的机器上以分布式的方式进行部署运行。

Message类是验证后数据的类别,用fsharp的Discriminated Unions相较于c#可以更简洁的表述简单的类别信息。

各类中OnReceive是每个Actor的核心所在,表述该Actor所代表的状态机。最近在思考设计的过程中越来越觉得状态机与事件是很多系统的核心。事件或者可以认为是系统的功能接口,代表着系统的外在表现。状态机则是系统内在的灵魂,在其合法的状态之间跳转,游荡。突然想到两者能结合么?状态事件?事件状态机?以后查查资料。

Prop生成Actor不能使用fsharp的Expr,以后再找找解决方案。

上面的例子在fsi中控制台的输入似乎不能很好的处理。我在注释1,2 处手动触发消息流转,也能实现例子中的效果。