6.1 模塊化程序設計
一個較大的程序一般應分為若干個程序模塊,每一個模塊用來實現一個特定的功能。所有的高級語言中都有子程序這個概念,用子程序實現模塊的功能。比如在C語言中,子程序的作用是由函數完成的,一個C程序可由一個主函數和若干個函數構成,由主函數調用其它函數,其他函數也可以相互調用,同一個函數可以被一個或多個函數調用任意多次。在Blockly中,也支持函數的定義和使用。

在程序設計中,常將一些常用的功能模塊編寫成函數,放在函數庫中供公共選用,所以要善於利用函數,以減少重復編寫代碼的工程量。
6.1.1 函數的定義形式
在C語言和別的語言中,函數的一個明顯的特征就是使用時帶括號(),必要的話,括號中還要包含數據和變量,稱為參數(Parameter),參數是函數需要處理的的數據。根據參數的有無,可將函數簡單的分為無參函數和有參函數。
這段話對於沒有接觸過C語言或其他編程語言的同學可能比較抽象,不過不必擔心,接下來我們會通過Blockly向您詳細的解釋。
(1)無參函數的定義

上圖是我們從Blockly工具箱中拖出的一個函數塊,其中:對函數進行參數的設置,無參函數不需要用到此選項

對工具箱中的Blockly有了簡單的了解之后,嘗試動手設計自己的函數。

上圖是一個簡單的無參函數,它的函數名就叫“無參函數”,當你從工具箱拖動一個塊在編輯區的同時,在工具箱中的函數選項卡中會生成一個對應的函數塊,當再用到此函數時,就可以像使用其他工具箱中的塊一樣直接使用。

(2)有參函數的定義 與無參函數不同,有參函數需要在“設置”中對參數進行設置,拖動“輸入名稱:x”至右側“輸入”中,並對參數進行命名即可。

同時,像無參函數一樣,你也可以在左側工具箱“函數”選項卡中看到對應的塊。

(3)函數的返回值 函數的另外一個明顯的特征就是返回值,既然函數可以進行數據處理,那就有必要將將處理結果告訴我們,所以很多函數都有返回值,所謂的返回值就是函數的執行結果。

當創建的函數需要返回值時,可直接從工具箱中拖動自帶返回值的函數塊,可見工具箱中生成的函數塊左側帶有凸起的連接。

這種方式生成的函數,只有當函數執行完成后才會返回值,如果在函數執行過程中就已經產生了想要的結果,也可以拖動"如果..返回"結束正在執行的函數,並返回執行結果。
注意: "如果..返回"在使用時,只有當函數最初設計有返回值時才有返回值,否則只是簡單的結束正在執行的函數。

下面來做一個小練習,設計一個求x, y中最大者的函數,名為Max(x, y)。

可以按照思維導圖,一步一步進行Max(x, y)函數的設計。在進行程序設計時,無論你是簡單的學習,還是進行復雜的開發,在動手之前,一定要對你所設計的程序有一個良好的規划,磨刀不誤砍柴工,好的習慣很重要,它可以加速你編程水平的提升,提高你的編程效率。

當你設計完成后,剩下的就是測試驗證程序結果了,測試時不需要很復雜,如果可以,最簡單的就是使用"打印"。

6.2 Blockly開發工具
在前幾章的學習中,每章開篇我們的小游戲環節,每個小游戲雖然是可視化編程,和我們學習的Blockly很像,但是又有所不同,而這些不同由何而來?這就是我們本章所講的重點,Blockly開發工具(Blockly Developer Tools),通過它用戶可以自定義新塊,這使得Blockly可擴展性大大提升,同時也是Blockly的靈活和強大之處。

本節面向希望在Blockly中創建新塊的開發人員。它的基本要求是,有一個

可以編輯的Blockly的本地副本,大體上熟悉了Blockly的使用,並且對JavaScript有一個基本的理解。

Blockly帶有大量的預定義塊,從數學函數到循環結構的一切,然而為了與外部應用程序接口,必須創建自定義塊以形成API。 例如,當創建繪圖程序時,可能需要創建“繪制半徑R的圓”塊。而在大多數情況下,最簡單的方法是找到一個已經存在的真正相似的塊,復制它,並根據需要修改它。
第一步是創建一個塊; 指定其形狀,字段和連接點。 使用Blockly Developer Tools是編寫此代碼的最簡單的方法,或者,可以在學習API之后手動編寫該代碼,高級塊可以響應於用戶或其他因素而動態地改變它們的形狀。
第二步是創建生成器代碼以將新塊導出為編程語言(例如JavaScript,Python,PHP,Lua或Dart)。為了生成既干凈又正確的代碼,必須注意給定語言的操作列表順序,創建更復雜的塊需要使用臨時變量和調用函數,當輸入使用兩次並需要緩存時,這是尤為重要的。
Blockly開發工具是一個基於Web的開發工具,可自動完成Blockly配置過程的各個部分,包括創建自定義塊,構建工具箱和配置Web Blockly工作區。
使用該工具的Blockly開發者進程包括三個部分:
1、使用塊工廠和塊導出器創建自定義塊。
2、使用Workspace Factory構建工具箱和默認工作空間。
3、使用Workspace Factory配置工作空間(當前是僅限Web的功能)。
6.2.1 定義一個塊

定義一個塊需要使用到Blockly開發工具中的塊工廠(Block Factory),塊工廠主要分為三個區域:
(1)編輯區:對新增塊進行設計和編輯
(2)預覽區:對編輯區編輯的塊進行實時預覽
(3)代碼區:代碼區分為兩個部分Language code和Generator stub,其中Language code 區指定和控制新增塊所呈現的形狀,Generator stub區負責新增塊所要生成的代碼。
在編輯區的左側,可以看到4個基本塊,Input,Field,Type和Colour,它們是四個原料庫,使用者可以從這些庫中獲取所需要的任意“原料”,來合成自己的新塊。

先從最簡單的介紹,顏色(Colour)塊,它默認定義了九種基本顏色,直接將你想要的顏色拖到右側,拼接到對應的colour的凹槽,便可立即在預覽區看到新塊的顏色。


如果默認色彩中沒有你想要的顏色,可以拖動任意色彩塊到編輯區拼接完成后,點擊色塊中的數字,在色塊的下方出現一個圓形的調色盤,轉動調色盤,選擇你喜歡的顏色。

在Blockly中,同一類型的塊通常采用相同的顏色,所以新塊的顏色選擇不能僅憑喜歡,還需要前后兼顧。
一個新塊不僅需要有顏色,還需要與其他塊進行銜接,這就需要設計新增塊的輸入和輸出,它們將決定新增塊的功能、屬性和類別。<>br 接下來看一看輸入(Input),這是新增塊與其他塊連接的接口之一。

輸入可以分為三種類型:值輸入(value input),聲明輸入(statement input),模擬輸入(dummy input)。首先以值輸入為例,拖動值輸入至右側與Inputs連接,可看到預覽區新增塊多了一個凹槽:

根據需要,使用者還可以添加多個輸入值,但要注意多個輸入值的名字不能相同,否則會出現警告,而且在后續調用的時候,也會沖突報錯,新塊名字也是如此,不能與其他塊同名,就好比如果班里有兩個學生名字一樣,那老師點名提問的時候就有可能出現兩個同學同時起立的尷尬。

在值輸入中還可以添加域(field),比如加入最簡單的文本域,即可在輸入中提示對應的文本,域中的下拉選擇框可設置文本的對齊方式。

這些設置完畢,選擇新塊的輸入方式,擴展式和嵌入式:

有了輸入之后,別的塊就可以很容易的通過凹槽加入到新塊了,但是,這時另外一個值得考慮的問題又出現了,怎樣將新增塊加入到其他的塊之中呢?我們有五種選擇:

看完值輸入之后,再一起來看一下另一個常用的輸入類型,聲明輸入(statement input),它通常用作條件控制和循環控制。

使用值輸入和聲明輸入,可以很容易的設計出編程中常用的條件語句和循環語句:

任務一:自己動手定義一個新塊,並描述它的功能。
6.2.2 管理庫
塊由其名稱引用,因此要創建的每個塊都必須具有唯一的名稱。 用戶界面強制執行此操作,並在您“保存”新塊或“更新”現有塊時清除。


您可以在先前保存的塊之間切換,或通過單擊庫按鈕創建新的空塊。更改現有塊的名稱是快速創建具有類似定義的多個塊的另一種方法。

6.2.3 導入和導出庫
塊被保存到瀏覽器的本地存儲,清除瀏覽器的本地存儲將刪除您的塊。 要無限期保存塊,您必須下載庫。 您的塊庫將下載為可導入的XML文件,以將您的塊庫設置為下載文件時的狀態。請注意,導入塊庫將替換當前的庫,因此您可能需要先備份導出。
導入和導出功能也是維護和共享不同組自定義塊的推薦方式。

6.2.4 塊導出器
如果你設計了塊,並且想要在應用程序中使用它們的時候,可以在塊導出器重完成塊定義和生成器的導出。
存儲在塊庫中的每個塊都將顯示在塊選擇器中。 單擊塊以選擇或取消選擇要導出的塊。 如果要選擇庫中的所有塊,請使用“選擇”→“所有存儲在塊庫”選項。 如果使用“工作區出廠”選項卡構建了工具箱或配置了工作區,則還可以通過單擊“選擇”→“在工作區工廠中使用”選擇所有使用的塊。

導出設置允許您選擇要定位的生成語言,以及是否需要所選塊的定義。 選擇這些文件后,點擊“導出”即可下載文件。

6.2.5 工作區工廠
工作區工廠可以方便地配置工具箱和工作區中的默認塊組。 您可以使用“工具箱”和“工作區”按鈕在編輯工具箱和起始工作區之間切換。

(1)構建工具箱 此選項卡有助於構建工具箱的XML,該材料假定使用者熟悉工具箱的功能,如果您在此處要編輯工具箱的XML時,可以通過單擊“加載到編輯”加載它。 (2)沒有類別的工具箱 如果您有幾個塊,它們沒有任何類別,想要顯示它們的時候,只需將它們拖動到工作區中,您將看到您的塊出現在工具箱的預覽中。

(3)有類別工具箱 如果你想要顯示塊類別,點擊“+”按鈕,並選擇下拉項目為新類別。 這將向您的類別列表中添加一個類別,您可以選擇和編輯。 選擇“標准類別”以添加單個標准塊類別(邏輯,循環等)或“標准工具箱”以添加所有標准塊類別。 使用箭頭按鈕重新排序類別。

要更改所選類別名稱或顏色,請使用“編輯類別”下拉菜單。 將塊拖動到工作區中將將其添加到所選類別。

(4)選擇工作區選項 為配置選項設置不同的值,並在預覽區域中查看結果。 啟用網格或縮放會顯示更多配置選項。 此外,切換到使用類別通常需要更復雜的工作空間; 當您添加第一個類別時,會自動添加垃圾桶和滾動條。

(5)將預加載塊添加到工作區 這是可選的,但如果要在工作空間中顯示一組塊,則可能需要: a當應用程序加載時顯示
b當觸發事件(提高級別,單擊幫助按鈕等)時顯示
將塊拖動到編輯空間中,可以在預覽區中查看它們。 您可以創建塊組,禁用塊,並在選擇某些塊時創建陰影塊。

(6)導出 工作區工廠提供以下導出選項:

◎Starter Code:生成html和javascript以注入您的自定義Blockly工作區。
◎工具箱生成XML以指定您的工具箱。
◎工作區塊生成可以加載到工作區中的XML。
(7)更多創建自定義塊的信息,可參考Google Blockly:
https://developers.google.com/blockly/guides/create-custom-blocks/overview
6.3 Blockly的高級使用
在之前的學習中,我們通過使用Blockly,學習一些基礎程序設計中的經典的例子,並通過Blockly的可視化代碼編輯器,進行了編程的實踐練習,我們所接觸和使用的這些,並不是Blockly設計的初衷。Blockly是一個庫,它為Web和Android應用程序添加了一個可視化代碼編輯器,Blockly編輯器使用互鎖的圖形塊來表示代碼概念,如變量,邏輯表達式,循環等,它允許用戶應用編程原則,而不必擔心語法或命令行上閃爍的光標。
6.3.1將Blockly作為代碼生成器
每個人不可能精通甚至熟悉每一種語言,但有時候,在學習、工作中又可能會用到所未接觸過的語言,如果我們沒有額外的時間且精力,尤其當這種語言再極少使用時,我們可能不樂意去花時間和精力去學習,但又不得不用,於是經常陷入兩難。針對這一常見現象,我們就可以使用Blockly作為代碼生成工具。
(1)假如現在我們需要一個判斷平年閏年的Python代碼的小例子,但我們之前又沒接觸過Python,我們又不想學習Python,那么就可以打開Blockly,在編輯區拖動塊來編寫:

拖動完成,驗證無誤,點擊Python選項卡,復制代碼至你的Python環境中,即可直接運行。

Python環境中的運行結果:

(2)假如現在需要一個JavaScript的執行腳本,而且我們對JavaScript也有所了解,我們也可以嘗試在Blockly中進行編程開發,比如這個猜數字的小游戲:

上面是程序的主體部分,包括循環、提示和中斷。

在程序之前,創建了三個變量並進行了初始化:
步長:用於計數,針對猜的次數進行不同的提示。
Target:存放隨機生成的目標數,與所猜數Number進行比較。
Flag:開關變量,用於標記是否猜對,從而決定是否提示下方內容。

同樣,驗證無誤后,點擊JavaScript選項卡,復制js代碼並保存。



將保存后的js代碼導入到html文件中測試。

當然,也可以把猜數字小游戲的Python代碼導出,同樣可執行。

注意:
◎ Python代碼的導出執行,當程序涉及輸入且輸入的是數字時,需要使用int(),將輸入的字符串型“數字”強制類型轉換成整型。


如果不進行強制類型轉換,執行腳本時可能會報錯,即使不報錯,結果也可能不正確。但這一問題在JavaScript導出代碼中不存在,兼容性良好。

◎對於JavaScript代碼的測試,可以導入到html中,在瀏覽器中執行,測試效果與Blockly中效果相同。html代碼如下:

本條注意事項專門針對沒有JavaScript基礎,但是對Blockly代碼生成工具又感興趣,想親手測試驗證的讀者。 關於Blockly作為代碼生成工具的使用,我們這里只舉了兩個基礎的,有代表性的例子,當然如果你學有余力或者對所生成的目標代碼十分熟悉,可以自行嘗試更加有趣、更加復雜的例子,如果你覺得這並不能滿足你的需求,那么可以嘗試自己動手定義你想要的塊,生成代碼的格式、類型和種類。
6.3.2 Blockly的二次開發
隨着Blockly逐漸的完善,它被越來越多的人所熟知,同時,憑借它可視化編程,良好的可擴展性等特點,很多的開發者利用Blockly進行二次開發,因此衍生出許多優秀的產品和工具。


前面曾提到過,Blockly的初衷是針對開發人員設計的,它是一個針對有經驗的開發人員的復雜庫。從用戶的角度來看,Blockly是一種直觀,可視化的構建代碼的方法。從開發人員的角度來看,Blockly本質上是一個包含正確語法、生成代碼的文本框, Blockly可以導出多種語言,例如JavaScript,Python,PHP,Lua,Dart等,下面是對Blockly進行二次開發的步驟:
a.集成塊編輯器。 Blockly編輯器包括用於存儲塊類型的工具箱和用於排列塊的工作空間。
b.創建應用程序的塊。 一旦你的應用程序中有Blockly,你就需要創建塊供用戶編碼,然后將它們添加到您的Blockly工具箱。
c.構建應用程序的其余部分。 本身,Blockly只是一種生成代碼的方法, 你的應用程序的核心在於如何處理該代碼。
可能單純的文字描述比較抽象,難以理解,以FreDuino為例,它是基於Blockly二次開發而成的一個遠程硬件控制平台。

a.集成塊編輯器,在工具箱里增添了與硬件外設進行交互的編碼塊。

b.創建應用程序塊,實現了Blockly塊與硬件控制代碼之間的轉換。

c.在構建應用程序部分,通過與硬件外設建立通信,實現代碼的上傳,進而完成與硬件的交互。

FreDuino就是通過上述三個步驟而誕生的,實現了對硬件外設的遠程可視化控制。

課后習題
1. 寫一個判斷素數的函數,在主函數輸入一個整數,輸出是否是素數。
2. 設計定義一個自己的工具塊。
3. 編寫函數,給出年、月、日,計算該日是該年的第n天,並嘗試將其導出的代碼在其他語言環境中調試運行。
知識梳理
