1. 程式人生 > >Java程式設計也要從娃娃抓起

Java程式設計也要從娃娃抓起

因為市面上沒有教孩子程式設計的教程書,於是本文作者自己編了一本。InfoQ的使用者朋友們有沒有教自己孩子程式設計的呢?我司倒是有一個教自家跳小蘋果的孩子學C語言的。

十二年前,我的小兒子Dave出現在我的辦公室,手裡拿著Java教程。Dave讓我教他程式設計,這樣他就能自己寫遊戲了。

那時候我已經寫了幾本關於Java的書,還同時教幾門計算機程式設計課,但那都是面向成人的;Amazon上沒有任何適合用來教孩子程式設計的書。在Google上搜索了幾個小時,我能找到的一些為孩子準備的程式設計教程也只是淺嘗輒止,或者是最基礎的那種類似於“聰明兔(譯者注:即reader rabbit,美國著名幼兒教育品牌)”的書。所以我決定自己寫一本書。

那時我的大兒子Yuri在大學裡主修動漫,他答應為我的書畫插圖。當我完成草稿的時候,沒有出版商願意出版它,原因有兩個:

少兒程式設計書根本沒有市場。
我希望這本書能彩印,較之於黑白印刷,這大大增加了成本。
沒什麼大不了的。我在網上釋出了此書的pdf版本供大家免費下載。一年後,幾位好心的法國家長把它譯成了法語,然後一些來自東歐的Java愛好者又把它譯成了俄語和烏克蘭語。這些版本仍然可以從網上免費下載到。

今年早些時候,我收到了一封意外的電子郵件,來自於No Starch出版社——問我是否有興趣寫一本給孩子看的Java程式設計書籍?我又問了一次,“你們願意彩印嗎?”,出乎我意料的是,他們馬上同意了,並且給我看了很多他們出版的教孩子程式設計的書籍,是其他語種的。時代變了……長話短說,我接受了。一年很快要過去了,這本書將會在2015年春季付印。

用Java來教孩子程式設計好嗎?

為了回答這個問題,我們首先要定義“孩子”這個詞。對於12歲以下的孩子來說,我相信Java作為第一門程式語言有點太複雜了。低齡一點的孩子一開始最好用一些寫好的程式模組來搭建視覺化程式。MIT建立了Scratch,對於8歲大的孩子來說,它是一個很好的激發程式設計興趣的工具。10歲的小孩就可以更進一步,通過Greenfoot開始學習真正地使用Java來程式設計。

但是我認為,任何12歲以上的孩子,只要對程式設計有興趣,就可以一本正經地去學習Java程式設計了,並且可以使用專業的工具來學。在之前為孩子寫的那本書裡,我使用Eclipse作為IDE,但在現在這本新書裡,我選擇了IntelliJ IDEA社群版,它也是免費的。

教成人和教小孩Java的區別在於,孩子們對於編寫GUI程式的反響更熱烈,而Java也很擅長做這個。我說的是JavaFX;Swing框架已經過時了,想用Swing來寫出點像樣的程式,需要很專業的知識。

JavaFX則提供了豐富的工具,並且非常優雅地隔離了介面和應用邏輯。JavaFX自帶了“Scene Builder”,一個視覺化的GUI設計工具,它可以生成用FXML描述的GUI;FXML是一種基於XML的語言,可以通過宣告的方式來建立GUI。不過不用擔心,孩子們不需要自己去寫FXML——他們只需要把UI控制元件拖拽到畫布(canvas)上,Scene Builder就會生成FXML。

少兒Java教育家

如果說12年前的孩子對程式設計還不是那麼感興趣的話,那麼今天的很多孩子已經很喜歡程式設計了。時代變了,於是,世界各地都有程式設計愛好者在花時間和精力給孩子介紹程式設計。我們要向Stephan Janssen致敬,他創立了Devoxx4Kids運動,用一種創造性的方式來教孩子程式設計。

這種運動最早開始於比利時,但如今很多國家都加入了。在美國,舊金山分會的領導人是Arun Gupta,而Matt Raible運營著丹佛分會。如果有位於曼哈頓的公司願意提供場地給孩子們搞活動的話,我已經準備好貢獻我的時間,在紐約建立一個分支機構。

我要為Stephen Chin獻上掌聲,他來自Oracle,他經常揹著一個袋子滿世界走,那個袋子裡裝滿了可程式設計裝置。今年早些時候,我參加了他的演講“瑪麗有個小小的lambda表示式”(譯者注:英文名“Mary Had a Little Lambda”,此名字借用了著名的英語兒歌“Mary Had a Little Lamb”,lamb和lambda詞形相近),在演講中他通過演示覆雜的遊戲解釋了Java。

今年夏天,我參加了在希臘舉行的JCrete“非會議”(譯者注:unconference,一種顛覆傳統式會議的新形式,會議內容由參與者自己制定,主張開放式討論)。其他與會者都帶著膝上型電腦來,Stephen卻帶來了兩打硬體開發套件,他舉行了一個研討會,在會上孩子們用Java編了一個機器人,可以跳Sirtaki舞(譯者注:希臘民間舞蹈)。

我肯定世界各地還有其他的好心人在給孩子們普及Java。已經誕生20年之久的Java語言正在越變越年輕。

本書節選

感謝有這樣的機會能給InfoQ的讀者呈現我將要出版的書籍“Java for Kids”中的兩段節選。在本書中我使用了IntelliJ IDEA社群版,JetBrains出品的免費又好用的IDE。第一段節選是關於類和物件的簡單介紹。第二段來自於Tic-Tac-Toe(譯者注:一種棋類遊戲)章節。教孩子的時候,程式的視覺化程度越高越好。這就是為什麼我要在總共12章中的5章都使用了JavaFX。讀者們需要編寫一個計算器和兩個遊戲:Tic-Tac-Toe和Ping-Pong。

本書節選1:類和物件

在現實世界中你會看到和用到各種物件,每個物件都屬於某個“種類”,比如玩具、食物、動物、電子產品等等。在Java中我們不說一種物件,而說一類物件。類就像是一個物件的藍圖。你將要編寫的所有程式都是由各種類組成的。

Java定義了各種資料型別。有些很簡單,像int,代表整數。有些複雜一點,它們就是類。比如System類,它可以用於在螢幕上列印文字、退出程式或清理計算機的記憶體。

你安裝了Java後,數千個Java類被下載到你的計算機中。你的Java程式中包含的類也可能代表來自真實世界的物件。如果說類是一種資料型別,那麼物件就代表了一種特殊的型別。舉個例子,你看到街上有十隻狗,他們都代表了Dog這個類。

程式設計師在開始寫程式之前,先要決定需要使用哪些類,每個類要建立多少物件。比如,在遊戲應用中他們可以定義Player類,並以此建立兩個物件。

當程式設計師互相交流的時候,他們可能會說“對Player類做某些操作”或者“用Player物件做某些操作”。我們需要分辨類和物件這兩個詞的不同含義。

我們來看看Java類是如何組成的。最基礎的類可能什麼都不包含。看看下面的類宣告:

class VideoGame {}

這是個空的類——它不帶有任何資訊,也幹不了任何事,因為兩個大括號之間沒有任何程式碼。從Java語法的角度看,這個類是合法的,計算機不會報錯——class是一個有效的關鍵字,緊接著是名字VideoGame,大括號要成對出現。但如果我們的程式想幹點什麼,我們需要定義有實際意義的類。所以我們需要給類加裝方法和屬性:

方法定義了一個類所能做的操作。
屬性描述了一個類的各種性質。
我們來給VideoGame類填上內容。這個類可以有一些方法,告訴我們這個類的物件能做什麼:開始遊戲、停止遊戲、儲存分數、要求上Facebook點贊等等。這個類也可以有一些屬性(也叫域):顏色、價格和其他。代表VideoGame類的一個物件看起來是這樣的:

class VideoGame {
String color;
int price;
void start () {
// 開始遊戲的程式碼放在這裡
}
void stop () {
// 停止遊戲的程式碼放在這裡
}
void saveScore(String playerName, int score) {
// 儲存分數的程式碼放在這裡
}
}**

這個類有兩個屬性color和price。color屬性是String型別的,這種型別用於儲存文字。price是int型的,用於儲存整數。VideoGame類有三個方法:start、stop和saveScore。這些都是我們的視訊遊戲能採取的動作。目前,這些方法只有以雙斜槓//開頭的一行字。

如果一行文字以雙斜槓開頭,那它就是單行的註釋——只是對程式碼段的描述。如果你需要寫多行的註釋,只要輸入一個斜槓和一個星號/,然後輸入任意行的文字,最後以一個星號和一個斜槓結尾/,代表註釋結束。

我們不會去創造一個真正的視訊遊戲,因為我們才開始學程式設計。但到本書的後面部分,我們會開發Tic-Tac-Toe和Ping-Pong遊戲。

但是難道你不覺得所有遊戲都有共同點嗎?每個遊戲都需要有一種方法來開始和停止或儲存分數。當你以面向物件的方式編寫一個程式,你要開始思考如何使類擁有的屬性和方法保持絕對的最少。然後你可以基於第一個類來新增更多特殊的功能——在本章節後面部分你會學到繼承。這就是為什麼VideoGame類只擁有視訊遊戲所共有的屬性和方法。

Java程式設計也要從娃娃抓起

圖1:視訊遊戲的物件

類還是物件

在本節中我將向你展示如何基於類來建立物件例項,並向你介紹繼承的概念。

為了複用你或者其他人已經寫好的程式碼,你可以基於一個類建立另一個,它會繼承前一個類的所有屬性和方法。繼承別的類建立的類稱為“子類”,被繼承的類稱為“父類”。下面的程式碼展示了繼承VideoGame類的新類PlayStation4。

class PlayStation4 extends VideoGame{```

String hardDiskSize;
// 其他屬性和方法可以在這裡宣告
// 方法shareOnFacebooks檢查使用者是否已經登入了
// 如果沒有,它會顯示一個視窗,帶有以下資訊
// “在分享你的分數之前請先登入Facebook”
void shareOnFacebook(){
// 在Facebook上分享的程式碼在這裡
System.out.println("Hey, Facebook, I got PlayStation4 with " + hardDiskSize);
}
void shareOnTwitter(){
// 在Twitter上分享的程式碼在這裡
System.out.println("Hey, Twitter, I got PlayStation4 with " + hardDiskSize);
}
}

語句extends VideoGame表示PlayStation4類是VideoGame類的子類。我們也可以說PlayStation4類繼承了VideoGame類或者說“擴充套件”了VideoGame類,這也意味著子類(PlayStation4)既可以使用父類(VideoGame)中定義的屬性,也可以使用父類(VideoGame)中定義的所有方法(並擴充套件它們),我在書的後面部分會解釋。

注意PlayStation4類即使沒有定義屬性price和color,以及方法start、stop和savaScore,但這個類的物件還是可以使用所有這些屬性和方法。它們是從VideoGame類繼承過來的,這些程式碼不需要拷貝/貼上到PlayStation4類中。

當我們建立一個物件的例項時,我們真正所做的是基於某個類的宣告,在計算機記憶體中建立了一個物件。舉個例子,下面的CreatePlayStation4Objects程式使用new運算子建立了兩個PlayStation4類的例項。

它聲明瞭兩個PlayStation4型的變數,分別是firstPlayStation和secondPlayStation,每個都指向了記憶體中的一個獨立物件。注意這些物件的屬性hardDiskSize有不同的值(500GB和1TB)。這個程式對第一個物件呼叫了shareOnFacebook方法,而對第二個物件呼叫了shareOnTwitter。

public class CreatePlayStation4Objects {
public static void main(String[] args) {
// 建立一個PlayStation4類的例項
PlayStation4 firstPlayStation = new PlayStation4();
firstPlayStation.hardDiskSize = "500GB";
// 對第一個例項呼叫shareOnFacebook方法
firstPlayStation.shareOnFacebook();
// 建立另一個PlayStation4類的例項
PlayStation4 secondPlayStation = new PlayStation4();
secondPlayStation.hardDiskSize = "1TB";
// 對第二個例項呼叫shareOnFacebook方法
secondPlayStation.shareOnTwitter();
}

執行CreatePlayStation4Objects會列印以下內容:

Hey, Facebook, I got PlayStation4 with 500GB
Hey, Twitter, I got PlayStation4 with 1TB

如果一個遊戲公司要生產10000個這樣的遊戲,那麼程式設計師可以說他們建立了10000個PlayStation4的例項。遊戲公司和一個真正的遊戲的關係就類似於Java類和它在記憶體中的例項的關係。在現實世界中游戲公司製作一個真正的遊戲,和Java程式設計世界中建立PlayStation4物件例項類似。只是每個例項會有些不一樣,比如本例中的內部磁碟大小。

Java程式設計也要從娃娃抓起

圖2:一個類,兩個例項

一般情況下,程式先建立Java類的物件例項,才能使用它的屬性和方法。遊戲公司也一樣——他們使用同一份原本生產出數千份遊戲拷貝。即使這些拷貝代表了同一個類,它們還是可能有不一樣的屬性——有些是黑的色,另一些則是銀色的。有些有500GB硬碟,有些則有1TB。

本書節選2:改變樣式和使用效果

這是第十章的節選,讀到那裡讀者已經掌握了JavaFX的基礎,寫過一個登入視窗和一個計算器,並且知道如何在介面上應用CSS樣式。Tic-Tac-Toe遊戲的基本功能也已經實現,但是如果能使制勝的三顆棋子一目瞭然就更好了(譯者注:Tic-Tac-Toe以三子在一直線上為勝)。

加亮制勝棋子

制勝棋子的樣式應該可以動態改變(在執行的時候)。首先,我們需要給CSS檔案新增一個樣式來顯示制勝的X-O棋子。然後Controller類可以對棋子呼叫setStyle方法,決定製勝的棋子使用哪種樣式。

我想改變制勝棋子的背景,但是這次我不想用單色了,我想用漸變色。在計算機圖形中,漸變色是指用混合的顏色去填充一個區域,並且相鄰顏色之間是平滑過渡。顏色漸變分線性的和放射狀的,這篇維基百科的文章有這兩者的例子。

我們的遊戲中使用放射狀漸變。我們可以使用兩種或更多的顏色來組成漸變色。我們給制勝棋子使用三種顏色吧。棋子的背景色會從白色轉變到淡×××,再到草綠色。棋子上的文字標籤,我們使用紅色。

要動態改變GUI元件的樣式,你可以呼叫setStyle,並指定顏色作為引數,舉個例子:

myButton.setStyle("-fx-text-fill: red;");

但是,在你的Java程式中寫死CSS規則不是一個好主意。如果你想改變樣式該怎麼辦(比如把顏色從紅色改成粉色)?你不想搜遍所有的Java檔案來找出所有使用這個樣式的地方。而且,改變嵌在程式碼中的樣式,會導致程式必須重新編譯,誰會為了一個簡單的修改這麼幹!所以把樣式定義放在外部的CSS檔案中會比較好,改起來就比較靈活。

至此,我們已經使用了CSS型別選擇器來改變指定元件的樣式。但是,CSS允許你定義一個樣式並給它取名,這樣,就不僅僅是特定的元件型別可以用它,各種元件都可以通過指定名字來使用它。在CSS中,這種樣式叫做類選擇器(class selectors)。我們來給tictactoe.css新增一個叫做.winning-square的類選擇器。

.winning-square {
-fx-text-fill: red;
-fx-background-color: radial-gradient( radius 100%, white, lightyellow, lawngreen);
}

這裡的樣式選擇器.winning-square包括了兩條樣式規則:一條是要把按鈕的顏色設為紅色,另一條是要把按鈕的背景色設為我們的放射狀漸變色。我們的Java程式必須得到按鈕現有樣式的引用,然後再新增一個.winning-square,這就會覆蓋按鈕原來的文字和背景顏色。方法highlightWinningCombo看起來是這樣的:

private void highlightWinningCombo(Button first, Button second, Button third){
first.getStyleClass().add("winning-square");
second.getStyleClass().add("winning-square");
third.getStyleClass().add("winning-square");
}

在給Controller類新增完find3InARow和highlightWinningCombo方法後,試著玩玩這個遊戲。制勝的棋子看起來就是下面這個樣子:
Java程式設計也要從娃娃抓起

圖3:我們贏了!

JavaFX包括了多種視覺效果和變換動畫,這些可以使你的介面變得更有意思。

要使用這些效果和動畫,你需要在javafx.scene.effect和javafx.animation包中進行相應的選擇。我會給你演示一下如何在我們的制勝棋子上使用淡出的變換效果。每個制勝棋子不停地淡出,然後又回覆到初始狀態。我們要給Controller類新增一個applyFadeTransition方法。

private void applyFadeTransition(Button winningButton) {
FadeTransition ft = new FadeTransition(Duration.millis(1000), winningButton);
ft.setFromValue(1.0);
ft.setToValue(0.1);
ft.setCycleCount(10);
ft.setAutoReverse(true);
ft.play();
}

這段程式碼建立了一個動畫類FadeTransition的例項,這個動畫會持續1000毫秒(等於1秒),然後把這個動畫分配給制勝棋子。然後它又設定了淡出的引數,把棋子的透明度從1改到了0.1(0.0意味著完全透明)。

把樣式數量設為10代表動畫會播放10次。因為呼叫了setAutoReverse(true),這個動畫會在第一個週期中正向播放,在第二個週期中反向播放,如此迴圈往復。play方法則啟動了動畫。給highlightWinningCombo新增以下三行程式碼,這個動畫就會在winningButton元件上播放。

applyFadeTransition(first);
applyFadeTransition(second);
applyFadeTransition(third);
下面的截圖告訴你動畫播放結束後的樣子。
Java程式設計也要從娃娃抓起

圖4:淡出的制勝棋子

把這張圖和前面一張比一比。或者執行書中的程式碼,看看動畫是什麼樣子的,就更好了。

喜歡小編輕輕點個關注哦!