従来の手続き型コーディング手法の欠点は明らかで、一定期間メンテナンスされていなかったコードや他人のコードを突然引き戻すと、元のコードを理解するのに時間がかかる、という経験がよくあります。このとき、文書やしっかりとした注釈があれば、もっと時間がかかるかもしれませんが、それでも、あえて変更する前に何度も確認をしなければならない呼び出し関係も多くあります。
次は、手続き型コーディング方法を説明する疑似コードの一部です:
func A(){ B() C() } func B(){ do something D() } func C(){ do something } func D(){ do something } func main(){ A() }
ストリーミング スタイルの記述方法を比較します:
NewStream(). Next(A). Next(B). Next(D). Next(C). Go()
手続き型スタイルのコードが関係を呼び出すとき複雑なプログラムであるため、エンジニアは注意深く慎重に行動する必要がありますが、フロー形式のコードと比較してクリーンでバックボーンが明確であるため、特に要件の変化に対応する場合に明らかな利点があります。
Java8 は、比較的完璧なストリーミング プログラミング スタイルを実装するためにラムダ式を借用しています。単純な言語である golang には、公式のストリーミング スタイル パッケージがありません (おそらくすでに存在しているでしょう。私が無知かもしれません))残念。
gorequest のコードを参考に、比較的一般的なストリーミング形式のパッケージを実装しました 実装原理は、タスクのリンクリストを形成し、各ノードが最初のノード、次のノード、そしてそのノードを保存することです。実行する関数ポインタ。ストリーミング タスクが開始されると、最初のノードから順に実行されます。例外が発生した場合、ストリーミング タスクは最後のタスクが実行されるまで終了し、タスク チェーンが終了します。 。まずはコードを見てみましょう:
package Stream import ( "errors" "fmt")/** 流式工作原理: 各个任务都过指针链表的方式组成一个任务链,这个任务链从第一个开始执行,直到最后一个 每一个任务节点执行完毕会将结果带入到下一级任务节点中。 每一个任务是一个Stream节点,每个任务节点都包含首节点和下一个任务节点的指针, 除了首节点,每个节都会设置一个回调函数的指针,用本节点的任务执行, 最后一个节点的nextStream为空,表示任务链结束。 **///定回调函数指针的类型type CB func(interface{}) (interface{}, error)//任务节点结构定义type Stream struct { //任务链表首节点,其他非首节点此指针永远指向首节点 firstStream *Stream //任务链表下一个节点,为空表示任务结束 nextStream *Stream //当前任务对应的执行处理函数,首节点没有可执行任务,处理函数指针为空 cb CB }/** 创建新的流 **/func NewStream() *Stream { //生成新的节点 stream := &Stream{} //设置第一个首节点,为自己 //其他节点会调用run方法将从firs指针开始执行,直到next为空 stream.firstStream = stream //fmt.Println("new first", stream) return stream }/** 流结束 arg为流初始参数,初始参数放在End方法中是考虑到初始参数不需在任务链中传递 **/func (this *Stream) Go(arg interface{}) (interface{}, error) { //设置为任务链结束 this.nextStream = nil //fmt.Println("first=", this.firstStream, "second=", this.firstStream.nextStream) //检查是否有任务节点存在,存在则调用run方法 //run方法是首先执行本任务回调函数指针,然后查找下一个任务节点,并调用run方法 if this.firstStream.nextStream != nil { return this.firstStream.nextStream.run(arg) } else { //流式任务终止 return nil, errors.New("Not found execute node.") } } func (this *Stream) run(arg interface{}) (interface{}, error) { //fmt.Println("run,args=", args) //执行本节点函数指针 result, err := this.cb(arg) //然后调用下一个节点的Run方法 if this.nextStream != nil && err == nil { return this.nextStream.run(result) } else { //任务链终端,流式任务执行完毕 return result, err } } func (this *Stream) Next(cb CB) *Stream { //创建新的Stream,将新的任务节点Stream连接在后面 this.nextStream = &Stream{} //设置流式任务链的首节点 this.nextStream.firstStream = this.firstStream //设置本任务的回调函数指针 this.nextStream.cb = cb //fmt.Println("next=", this.nextStream) return this.nextStream }
以下はストリーミングの例です。朝起きてから出勤するまでのプロセスです:
//起床func GetUP(arg interface{}) (interface{}, error) { t, _ := arg.(string) fmt.Println("铃铃.......", t, "###到时间啦,再不起又要迟到了!") return "醒着的状态", nil }//蹲坑func GetPit(arg interface{}) (interface{}, error) { s, _ := arg.(string) fmt.Println(s, "###每早必做的功课,蹲坑!") return "舒服啦", nil }//洗脸func GetFace(arg interface{}) (interface{}, error) { s, _ := arg.(string) fmt.Println(s, "###洗脸很重要!") return "脸已经洗干净了,可以去见人了", nil }//刷牙func GetTooth(arg interface{}) (interface{}, error) { s, _ := arg.(string) fmt.Println(s, "###刷牙也很重要!") return "牙也刷干净了,可以放心的大笑", nil }//吃早饭func GetEat(arg interface{}) (interface{}, error) { s, _ := arg.(string) fmt.Println(s, "###吃饭是必须的(需求变更了,原来的流程里没有,这次加上)") return "吃饱饱了", nil }//换衣服func GetCloth(arg interface{}) (interface{}, error) { s, _ := arg.(string) fmt.Println(s, "###还要增加一个换衣服的流程!") return "找到心仪的衣服了", nil }//出门func GetOut(arg interface{}) (interface{}, error) { s, _ := arg.(string) fmt.Println(s, "###一切就绪,可以出门啦!") return "", nil } func main() { NewStream(). Next(GetUP). Next(GetPit). Next(GetTooth). Next(GetFace). Next(GetEat).//需求变更了后加上的 Next(GetCloth). Next(GetOut). Go("2018年1月28日8点10分") }
上記よりコード、ストリーミング コーディング 大きなタスクが複数の小さなタスクに分解された後、このスタイルはコード レベルで非常に直感的です。どれがどれを呼び出しているかを見つけるために苦労する必要はもうありません。また、要件の変更も簡単です。上の例では、朝食を食べることは、最初のバージョンで実装されていなかったのは、顧客が午前中に食べなければならない、そうしないと胆石になりやすいと言ったことです。2 番目のバージョンを追加する必要があります。食べる関数を作成し、それを応答位置に追加します。手続き型コーディングと比較すると、はるかに単純です。
golang 関連の技術記事をさらに詳しく知りたい場合は、golang チュートリアル列をご覧ください。
以上がGolang でのミニマリスト フロー プログラミングの詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。