張璞 夏英



摘 要:Java程序設計課程學習過程中,學生面臨面向對象編程思維方式轉換困難,難以靈活應用面向對象特性等問題。針對這些問題,提出將軟件設計模式有機融入于課程教學的教學模式。闡述了教學模式的教學過程設計、在面向對象概念教學過程及Java SE類庫教學過程中軟件設計模式的應用,最后,對上述內容進行了總結。
關鍵詞:Java程序設計;軟件設計模式;面向對象;教學模式
中圖分類號:TP311 文獻標識碼:A
Abstract:In the learning process of Java programming course,students face the difficulty of converting to object oriented programming thinking mode,and it is also difficult for students to flexibly apply object-oriented characteristics.In view of these problems,the paper puts forward that the software design pattern should be organically integrated into the course teaching mode.It expounds the teaching process design of the teaching mode,and the application of the software design pattern in the teaching process of the object-oriented concept and Java SE class library.Finally,the above contents are summarized.
Keywords:Java programming;software design pattern;object-oriented;teaching mode
1 引言(Introduction)
作為一種面向對象程序設計語言,Java由于具有面向對象、平臺無關、安全性、內置多線程等眾多優良特性[1],已被廣泛應用于Web開發、智能手機、桌面應用等不同領域,是當前最流行的編程語言之一。作為程序設計教學的一個重要分支,國內外眾多高校均開設了Java程序設計課程,該課程已成為一門重要的專業基礎課。
Java程序設計課程教學過程中,需要將面向對象編程思維的培養作為重點,并貫穿于教學過程始終,使學生能夠靈活運用面向對象思想來解決實際問題。從實際情況來看,許多高校將C語言開設為第一門程序設計語言課程,因此,學習Java語言時,學生已經具備C語言基礎。由于受面向過程編程思想的影響,很多學生仍然存在由面向過程轉換為面向對象編程思維的困難。例如,在進行類的設計時,一些學生習慣于將許多靜態方法定義于一個類中,甚至覺得類只是在C語言函數的基礎上加個框而已。一些學生則陷于Java編程語法的記憶與機械理解之中,未能掌握面向對象編程語言的基本特征及概念,不熟悉使用類進行面向對象設計的基本原則,導致遇到具體問題時,不能靈活應用繼承、多態等面向對象特性,所實現代碼的可復用性、可擴展性差。
軟件設計模式是從許多優秀軟件系統中總結出的可復用設計方案[2,3]。文獻[2]最先將設計模式的概念引入軟件開發領域,經過分類編目后,歸納總結出了23種設計模式。已有研究表明[4,5],設計模式思想在面向對象程序設計教學中有重要的作用,把設計模式引入教學過程中,能使學生更加深刻地理解面向對象思想,了解面向對象設計的基本原則,提高編程能力,有助于開發更易維護、可擴展性強、復用性好的系統。
針對學生轉換面向對象編程思維困難,難以靈活應用面向對象特性等問題,通過教學實踐,筆者在不同教學模塊中有針對性、有目的性地引入一些經典設計模式,在教學過程中有機融入設計模式,取得了良好效果。下面對軟件設計模式在Java課程教學中的應用進行介紹。
2 教學過程設計(Design of the teaching process)
面向對象程序設計課程的教學核心不是學習設計模式[4],因此,在教學過程中,不需要學習全部設計模式,而需要緊密結合教學內容,挑選引入一部分設計模式來深化學生對面向對象編程思想的理解和靈活運用。表1給出了筆者在課程教學活動中所引入的設計模式。
表1中的“類和對象”“類的繼承”“接口”等教學模塊屬于Java中面向對象部分的教學內容,而“集合框架”“輸入輸出流”“圖形用戶界面”“多線程”等教學模塊則屬于Java SE類庫部分的教學內容。本文后續內容將分別介紹設計模式在以上兩部分教學內容中的應用。
在各個教學模塊的教學實施過程中,為了遵循學生的認知規律,激發學生的學習興趣,通過精心設計教學案例,筆者采用了“案例驅動”的設計模式教學過程,如圖1所示。
由教師先描述案例,介紹所需要解決的問題,讓學生帶著問題進入內容的學習,從而引起學生的好奇心。之后由教師對解決案例所用設計模式的意圖及模式結構圖進行介紹,根據模式結構圖的UML圖形描述來介紹模式結構中的各種角色,再從案例中分析得出各種角色所對應的類或接口,并用Java語言進行實現,得到案例的解決方案。最后,由教師對設計模式的效果、其中體現的面向對象思想及設計原則等進行歸納總結。
3 面向對象教學內容中引入設計模式(Introducing
design pattern into object-oriented teaching
content)endprint
3.1 通過設計模式來深化基本概念的理解
面向對象的核心思是將數據和對數據的操作封裝在一起形成對象,并通過抽象找出同一類對象的共同狀態和行為,從而得到類。Java程序的基本單位是類,編寫程序時要先定義好類,再由類實例化生成對象。“類和對象”是Java中的重要教學內容。在教學過程中,學生會接觸到許多新概念,例如類、對象、構造方法、類及成員的訪問權限、靜態變量、實例變量、靜態方法、實例方法等。在學習了這些基本概念的基礎上,筆者在教學過程中引入單例設計模式來加深學生對以上基本概念的理解。
教學過程中,首先讓學生了解在實際編程中,有些對象僅需要一個,例如操作系統中的打印池對象。繼而提出問題,如何保證設計的類在僅有一個實例對象。
案例設計:操作系統中,打印池(Print Spooler)是一個用于管理打印任務的應用,在系統中只允許運行一個打印池對象,要求使用單例模式來模擬打印池。
描述了案例后,再由教師介紹單例模式的意圖和模式結構圖,從案例入手,分析出單例角色類(PrintSpooler),給出案例的模式實現代碼:
class PrintSpooler {
private static PrintSpooler instance=null; //私有靜態成員變量
private PrintSpooler(){ } //私有構造方法
public static PrintSpooler getInstance(){ //公有的靜態方法
if(instance==null) {
instance=new PrintSpooler();
}
return instance;
}
public void print(){//實例方法
System.out.println("執行打印任務");
}
}
講解了模式實現代碼后,再由教師啟發學生思考并回答該模式的幾個要點:單例類為何要定義私有構造方法?為何要定義私有的靜態成員變量和公有靜態方法來保存和獲得對象實例?單例模式是如何保證對象實例的唯一性的?最后再總結單例模式的適用情況。通過將單例模式與Java面向對象語法相結合,逐步深入講解來加深學生對面向對象概念的理解。
3.2 通過設計模式來深化面向對象語言基本特征的理解
在學習面向對象語言的基本特征時,學生普遍感覺多態的概念比較抽象,難以理解。因此,筆者將模板方法模式引入到“類的繼承”教學模塊中,設計了模板方法模式來模擬銀行業務辦理流程的案例。
案例設計:客戶在銀行辦理業務時,一般都包含取號排隊、辦理具體業務、對工作人員進行評分等步驟。無論具體業務是取款、存款還是轉賬,其基本流程都是固定的。要求使用模板方法模式來模擬銀行業務的辦理流程。
敘述案例后,由教師介紹模板方法模式的意圖:定義一個操作中算法的骨架,而將一些步驟延遲到子類中,從而使子類可以不改變一個算法的結構即可重定義該算法的某些特定步驟。在此基礎上,給出模式的UML結構圖來介紹模式中所包含的兩個角色:抽象類(AbstractClass)和具體子類(ConcreteClass),然后從案例中引導學生根據模式結構圖來定義出案例中的抽象類和幾個具體子類,進而給出案例的模板方法模式實現代碼:
abstract class BankProcess{ //抽象類
public void takeNumber() {
System.out.println("取號排隊");
}
public abstract void transact();
public void evaluate() {
System.out.println("反饋評分");
}
public void process() { //模板方法
this.takeNumber();
this.transact();
this.evaluate();
}
}
class Deposit extends BankProcess { //具體子類:存款類
public void transact() {
System.out.println("存款");
}
}
… …
class Transfer extends BankProcess { //具體子類:轉賬類
public void transact() {
System.out.println("轉賬");
}
}
進行代碼講解后,由教師有意識地引導學生畫出上述實現代碼的UML類圖,如圖2所示,加深學生對程序結構和模式結構的理解。
再由教師引導學生思考繼承及多態性等特征在該模式中的體現,使學生認識到在模板方法模式中,子類可以體現多態性。即子類可以根據各自的需要覆蓋父類中定義的方法,由于面向對象的多態性,子類對象執行從父類繼承來的模板方法時,其中的方法調用將通過動態綁定方式來實現子類對父類行為的反向控制。最后,由教師總結歸納模板方法模式的適用情況。
3.3 通過設計模式來深化面向對象設計原則的理解
Java語言的學習過程中,掌握好面向對象基本語法和概念后,了解一下用類進行面向對象設計的基本原則,如“開放—閉合”原則、聚合復用原則、依賴倒轉原則等,不僅有助于加深學生對面向對象編程思想的理解,還有助于編寫出易維護、易擴展和易復用的程序代碼。endprint
在學習Java中“接口”部分教學模塊時,筆者引入了策略模式來幫助學生理解“開放—閉合”等設計原則。
案例設計:在多個裁判負責打分的比賽中,每位裁判給選手一個評分,選手的最后得分的評分方案(策略)可以有多種。如可以是所有評分的平均值,也可以是去掉一個最高分和一個最低分后的平均值。要求使用策略模式來從多種評分方案中選擇比賽的評分方案。
和前述教學過程類似,通過對案例進行描述及分析后,使學生了解清楚策略模式的意圖是定義及封裝一系列算法,并讓它們可以相互替換。然后再根據策略模式結構圖中的上下文(Context)、策略(Strategy)和具體策略(ConcreteStrategy)等不同角色找出案例中的對應類,進行代碼實現,并引導學生畫出如圖3所示的模式結構圖。
interface Strategy { //策略接口
public double computeAverage(double [] a);
}
class AverageScore{ //上下文類
Strategy strategy;
public void setStrategy(Strategy strategy){
this.strategy=strategy;
}
public double getAverage (double [] a){
if(strategy!=null)
return strategy.computeAverage(a);
}
}
class StrategyA implements Strategy{ //具體策略類
public double computeAverage(double [] a){
double score=0,sum=0;
for(int i=0;i sum=sum+a[i]; } score=sum/a.length; return score; } } class StrategyB implements Strategy{ //具體策略類 public double computeAverage(double [] a){ if(a.length<=2) return 0; double score=0,sum=0; Arrays.sort(a); //排序數組 for(int i=1;i sum=sum+a[i]; } score=sum/(a.length-2); return score; } } 接下來,由教師對模式中所涉及到的“開放—閉合”原則進行分析。上下文類AverageScore只知道它要使用某一個實現Strategy接口類的實例,但不需要知道具體是哪一個類,因此,當增加新的具體策略時,不需要修改上下文類的代碼,上下文就可以引用新的具體策略的實例。最后,教師對策略模式的主要優點及適用情況進行總結。使學生掌握策略模式通過對“開放—閉合”原則的完美支持,在不修改原有系統的基礎上可以更換算法或者增加新的算法,從而能很好地管理多種評分方案,提高代碼可擴展性。 4 J2SE類庫教學內容中引入設計模式(Introducing design pattern into J2SE class library teaching content) Java SE平臺的類庫設計中也應用了大量的設計模式,因此,在API類庫教學過程中,介紹所涉及的設計模式,一方面可以使學生更好地掌握類庫中相關類和接口的作用及功能;另一方面,也能使學生對面向對象思想及基本原則、設計模式的實際運用有更深的體會。因此,筆者在進行集合框架、輸入輸出、圖形用戶界面編程、多線程等內容的教學過程中,對J2SE類庫中所涉及到的典型模式也作了相應介紹。 在學習Java集合框架時,筆者引入了迭代器模式,通過介紹該模式來幫助學生更好地掌握集合框架的設計思想。JDK類庫中,Collection接口的iterator()方法返回一個Iterator類型的對象,java.util.Iterator接口就是迭代器模式的應用。通過迭代器模式訪問一個列表(List)或者一個集合(Set)對象的內容時,無需了解聚合對象的內部表示,使遍歷操作變得簡單。 在學習輸入輸出流時,Java中的I/O類庫由于其龐雜的特點,一直是學生學習的難點。為此,筆者在介紹I/O類庫的過程中,引入了裝飾模式來幫助學生掌握I/O類庫結構。在I/O處理中,Java將數據抽象為流(Stream),輸入流(Input Stream)、輸出流(OutputStream)類只提供最基本的數據讀寫功能。而FilterInputStream作為抽象裝飾類,BufferedInputStream、DataInputStream、BufferedOutputStream、DataOutputStream等類則作為具體裝飾類,這些類的設計很好地應用了裝飾模式,以透明的方式動態地給一個對象附加上更多的功能,這樣就可以在不需要創造更多子類的情況下,將對象的功能加以擴展。 在學習圖形用戶界面時,隨著教學內容的展開,筆者分別引入了組合模式、裝飾模式、策略模式、觀察者模式來介紹java.awt和javax.swing包中的類和接口。例如,介紹AWT/Swing庫中的組件類(Component)、容器類(Container)及系列子類的關系時,通過組合模式的介紹,學生很快地掌握了類庫中的大量組件類、容器類之間的關系。介紹容器的布局管理方式時,筆者有意識地啟發學生思考Java類庫中Container類、LayoutManager接口間的關系實際上就是策略模式的一個經典應用。介紹事件處理時,為了幫助學生深刻理解事件處理機制,筆者相應介紹了觀察者模式。在javax.swing包中,通過裝飾模式能動態地給一些組件增加新的行為或改善其外觀顯示。例如,JList組件本身并不支持滾動條功能,要創建可以滾動的列表,則需要使用JScrollPane類來作為裝飾器。 在學習多線程時,針對“類和對象”教學模塊中的單例模式實現代碼,由教師分析在多線程環境下所可能產生的線程安全問題。可以假設這樣一種情況:當第一個線程判斷引用變量為空之后,對象實例化過程尚未完成之前,第二個線程開始判斷引用變量是否為空。由于第一個線程尚未完成對象創建,因而引用變量instance還為空,這將導致第二個線程實例化第二個單例對象,從而導致不正常情況的發生。解決方法是通過線程同步控制機制,在getInstance()方法前加上synchronized關鍵字,通過對象鎖來實現線程安全的單例模式實現。 5 結論(Conclusion) 教學實踐證明,在Java程序設計課程教學過程中有機地引入設計模式的這種教學模式,將設計模式與面向對象的語法、概念、設計原則相結合,對培養學生的面向對象編程思維方式,提高編程能力等方面均有積極作用。這種教學模式也得到了學生良好的評價,學生的學習主動性、靈活運用面向對象特性解決問題的能力均得到了提高,為后續課程的學習及實踐應用奠定了良好基礎。 參考文獻(References) [1] 耿祥義,張躍平.Java面向對象程序設計(第2版)[M].北京:清華大學出版社,2013. [2] Erich G,et al.李英軍,等,譯.設計模式:可復用面向對象軟件的基礎[M].北京:機械工業出版社,2004. [3] 劉偉.設計模式實訓教程[M].北京:清華大學出版社,2012. [4] 楊瑞龍,朱征宇,朱慶生.引入軟件設計模式的面向對象程序設計教學方法[J].計算機教育,2012(10):97-100. [5] 章品正,於文雪.設計模式在C++課程教學中的運用[J].計算機教育,2014,218(14):41-45. 作者簡介: 張 璞(1977-),男,博士,副教授.研究領域:數據挖掘,自然語言處理. 夏 英(1972-),女,博士,教授.研究領域:數據庫與數據挖掘,時空大數據分析.