• 沒有找到結果。

第一章 序論

1.4 論文章節架構

探討,了解 Groovy 是如何使用後端物件協定 (Meta-Object Protocol, MOP)來 實作他們的程式架構。除此之外,有鑒於大學排課系統是限制條件滿足問題 (Constraint Satisfaction Problem, CSP) 我們也會對 CSP 做簡單介紹。而目 前現有的相關文獻討中也有學者對於此類問題提供搜尋演算法如:基因演算法、

禁忌搜尋法、模擬退火法以及模糊理論等。這部份我們也將一一做簡單介紹。

在第三章的系統架構與實作,裡面我們先將我們的大學排課問題做一個簡單

‧ 國

立 政 治 大 學

N a tio na

l C h engchi U ni ve rs it y

5

的描述,並引出我們的系統整體架構。最重要的是,我們也將介紹本系統的兩大 使用者輸入介面:領域專屬語言(Domain Specific Language, DSL)以及 GUI 的 建制方式與使用說明。DSL 的部分,我們將談到 Groovy 是如何協助開發者撰寫 他們的 DSL。最後我們也談到我們如何利用條件限制處理器 ( Constraint Programming Solver ) JaCoP 來描述我們的問題,並將程式碼收錄在附錄之中。

第四章的部分,將直接進行實作範例。我們使用政大資科系與政大企管系做 為我們的測試範例,並將政大資科系該學期含學士班、碩士班以及博士班的排課 總結果收錄其中,並提供教室與教師的個別課程檢視模式。同時,我們也使用國 際競賽 Curriculum-Based Course TimeTabling (CTT) 的例子進行系統測試並 將其排課結果收錄其中。

‧ 國

立 政 治 大 學

N a tio na

l C h engchi U ni ve rs it y

6

第二章 相關研究探討

本研究的目的是希望在現有的限制條件中找出更能符合所有教師需求的課 表。我們建置 GUI 提供使用者一個能快速上手的排課工具,在此同時也利用 Groovy 快速開發 Domain Specific Language (DSL) 的特性來建立學校課程安排 系統的專屬領域語言。而中間的系統搜尋解部分則是採用限制條件語言 JaCoP 來 找出我們所需的課表。課表編排屬於限制條件問題(Constraint satisfaction problem) 在接下來的討論中我們將會介紹用來建制 DSL 很重要的宿主語言 Groovy 特性、CSP 的相關概念以及我們所處理的校園排課問題整理。同時,我們 也將介紹現有關於排課問題的相關文獻探討。

2.1 Groovy

Groovy 根植於 Java,而 Java 語言的特性在於他著重在 Strong Type 的撰寫 語法,使用此語法的好處是它在編譯時期易於排除錯誤,而執行時期則具有比較 優質的速度,但缺點是在撰寫程式時需要繁瑣冗長的輸入。以目前講求效率的市 場環境來說,程式撰寫上的繁瑣顯然不符實際要求。雖然說 JDK 本身仍有不斷的

類似 Java 和 Scripting 的結合[4]。2004 年 Groovy 誕生之後常被拿來和 Ruby 以及 Python 等其他 scripting language 來做比較,Groovy 本身嘗試擷取其他 直譯式語言的部分優點,並且將其程式碼編譯成 Java bytecode 來提升其執行效 能,再加上 JDK 本身長久以來的改進加持之下,使得 Groovy 本身能提供開發人 員撰寫程式上的極大的方便性跟操作空間。

Groovy 具有許多特性並且提供了許多內建工具,例如 Closure、GDK、Grails、

XML Builder、Swing Builder 等等。在此我們僅挑出與本研究相關的二點特性:

Meta-object Protocol(MOP)和 Groovy builder 來做介紹。

2.1.1 後端物件協定(MOP)

後端物件協定(Meta-Object Protocol)[26]是 Groovy 能夠快速開發程式的 主要原因。在 Java 平台撰寫 java 程式時,雖然我們可以利用信息傳遞(message passing)的方式,將信息送至不同接收者(receiver),以完成程式或服務叫喚。

但這協定及其傳統 OOP 的編譯與執行時期實作都過於死板,以至於程式師希望具 有的效果,往往必須經由其他迂迴冗長的程式設計方能達成。而 Groovy 提供了 MOP 機制來實作後端程式設計(metaprogramming)[27]以方便我們完成想要的程 式。

物件,Groovy 物件具有更大的使用彈性與便利,其緣由在於 Groovy 物件對於 method 呼叫的處理方式,與 Java 物件有很大的不同。

在 Groovy 的程式裡,我們可以運用到三種不同類型的物件,他們分別是 POJOs (Plain Old Java Objects)、POGOs (Plain Old Groovy Objects)跟 Groovy Interceptors。POJOs 是指利用 Java 或其他非 Groovy 語言創建,可在 JVM 執行 的原生 Java 物件;POGOs 則是指利用 Groovy 所寫的一般類別物件,它們繼承 java.lang.Object 但是實作 groovy.lang.GroovyObject 介面,至於 Groovy Interceptors 則是指實作 GroovyInterceptable 介面的 Groovy 物件。

Groovy 在 GroovyObject 介面裡定義了幾個重要的 method,確實內容如圖 2.1.1 所示:

圖 2.1.1:GroovyObject 介面

介面中的 invokeMethod()、getProperty()和 setProperty()可以方便我們 隨時動態的呼叫物件的實體方法和屬性。除此之外,在 JVM 上我們不能夠隨意的 去更改已經被讀進 JVM 的 metaobject 類別,但由於 MetaCalss 定義了其他 Class 的實作與 instances。所以我們可以透過 setMetaClass()的方式來進行程式上的

Groovy 允許我們對 POJOs、POGOs 來進行後端程式設計 (metaprogramming)。

對於 POJOs 而言,Groovy 事先會由 MetaClassRegistry 讀取登錄的 MetaClass,

在 MetaClass 裡面所定義的任何介面和實體方法都會比原本 POJO 本身的實體方 法具有更高的處理順位。

然而如果處理的是 POGOs,則所要進行的步驟就較為複雜。首先 Groovy 會 先確定該 POGO 物件是否實作 GroovyInterceptable?如果確有實做,則 Groovy 將 逕 行 呼 叫 該 POGO 的 invokeMethod() 而 完 成 函 式 呼 叫 處 理 。 有 了 這 種 interceptor 機制,程式師就可以利用實做 invokeMethod(),而達成截收並處理 呼叫者傳送給 POGO 物件的呼叫信息。利用 interceptor 機制,程式師將可輕易 改變信息發送者所能得到的接受者的服務 內容。然而如果 POGO 並未實作 GroovyInterceptable,則 Groovy 就會至 POGO 的 MetaClass 裡面找尋匹配的實 體方法予以執行,如果沒有匹配的方法,才會由 POGO 自己的實體方法中找尋。

如果連 POGO 裡面都找不到匹配的實體方法,則 Groovy 會試著去找找看是否有一 個屬性是用這個實體方法的名字,假如使用這個實體方法名字的是 closure,那 麼 Groovy 會直接呼叫這個 closure。如果連最後有同樣名字的 closure 都沒有 找到,那麼 Groovy 會去試著做兩件事,首先先試著呼叫看看 POGO 裡面是否有 methodMissing(),如果有,就執行,如果沒有,則呼叫 invokeMethod(),否則 最後就丟出 MissingMethodException()代表這次的方法呼叫失敗。整個過程的 流程之簡單圖式如下圖 2.1.2 所示。

‧ 國

立 政 治 大 學

N a tio na

l C h engchi U ni ve rs it y

10

圖 2.1.2:Groovy 處理 POGOs 流程

有了以上的 Groovy MOP 處理機制之後,使用者在處理 Groovy 的物件上會更 具有彈性以及方便,在《Groovy in Action》一書中,作者 Dierk Konig 也認為 MOP 提供了使用者幾個方便性:

1. 程式可以隨時插斷實體方法來進行 cross-cutting concerns,比方說安全檢 查、交易等等的系統層面服務。

2. 物件可以用來呼叫其他的物件實體方法。

3. 物件可以假裝執行那些不屬於自己卻好像自己就有的實體方法。

(builder),其中包括 XMLbuilder、SwingBuilder、AntBuilder 等等。使用者只 要依循著 Groovy 原先就定義好的 builder 描述方式撰寫,即能輕鬆產製程式碼,

使其在 runtime 產生所需之特殊應用領域物件。除此之外,Groovy 也利用其撰 寫程式上的方便以及快速性來提供使用者建立屬於自己的 builder。而我們就是 利用 Groovy 提供的這項優點來進行本研究所需之校園課表編排描述語言之開發。

接下來,我們將分別探討 Groovy builder 能夠利用哪些 Groovy 機制來提供我們 撰寫個人 builder 上的便利性。最後並淺談完成 Groovy builder 的一個很重要 的元件:BuilderSupport。

2.1.5 Groovy 特色介紹

當使用 Groovy 做為程式的開發工具時[6],使用者不需要去了解 Groovy 的 MOP 或者是 builder 機制是如何運行的,我們只需要知道如何利用這些 Groovy 特點來撰寫這些 builder 程式碼,以及讓它們符合正確的語法就可以加速我的程 式開發過程,其中這些使用 Groovy 開發的特點包括:

1. Closure method 呼叫:Groovy 利用 closure 的特性來完成其獨特的巢狀結構,

在 builder 處理的過程當中,我們甚至不用傳遞任何的參數。

2. Closure method 解決方法:當一個不存在某 closure 裡的實體方法被呼叫時,

Groovy 會使用一種特殊的解決方式來處理這個不存在的實體方法呼叫,它會 決定哪一個物件應該要去呼應這個實體方法呼叫。

3. Pretended method:前面所討論到的 Groovy MOP 機制讓 Groovy 可以呼叫那 些甚至不存在類別裡的實體方法,其實也就是「假裝」這些實體方法好像存 在。

4. Named parameters:當我們傳遞一個 map 參數到一個實體方法,Groovy 可以 將這個參數跟其他的實體方法參數一併傳出,這讓程式感覺就好像傳出了一 個 named parameter list。

5. Closure delegate:改變一個 closure 的 delegate 可以讓其他的類別來處理 他們的實體方法呼叫,當我們重新指定 delegate 到一個 builder 類別,這能 讓該 builder 能夠重新編排這些實體方法的處理方式。

2.2 限 制 條 件 滿 足 問 題 ( Constraint Satisfaction Problem)

所謂的限制條件滿足問題(CSP)就是指一組變數其值必須符合某些特定限制 (Eight queens puzzle), 地圖著色問題(Map coloring problem), 以及大家耳 熟能詳的數讀(Sudoku)問題等等。在本研究中,我們的限制條件則來自於課程的

制條件的規範過多,甚至可能會出現無法求解 (Over-Constrained) 的情況發生。

在這種情況下,解決方式往往必須要直接拿掉那些造成問題無解的限制條件,來 機率、程度的方式來滿足其部分需求。常見的解決方式例如 Hierarchical CSP[19]、Partial CSP[20]等,以下我們針對 Partial CSP 及 Hierarchical CSP 來作進一步探討。

2.2.2 部分式限制條件問題 (Partial CSP)

Partial CSP[20]是在變數子集合滿足部分的限制條件集合情況下,於值域 中再去尋求適合的變數值。學者 Tseng 將 Partial CSP 正式定義為:一個 Partial CSP 是由四個部分所組成 (Z, D, C, g),其中(Z, D, C)是一個基本 CSP 問題的 結構,而 g 則是依據問題所訂立的目標函數。

Partial CSP 的目的是將這些放鬆過限制條件的問題解答中找出一個與原定

Partial CSP 主要利用以下四個方式來放鬆問題的限制條件[35]:

1. 增加變數的值域範圍 2. 增加限制條件的彈性 3. 移除問題中的一個變數 4. 移除問題中的一個條件

Freuder 和 Wallace 認為 Partial CSP 可以用於以下的問題情況[20]:

1. 當問題條件過度限制(over-constrained)但是可以違反部分條件的狀況 2. 當問題過於複雜,而意圖只尋求滿意解時

3. 在滿足基本限制條件情況下,放鬆其他的部分限制條件以取得最佳解時 4. 當問題的求解具有時間限制的情況時

2.2.3 階層式限制條件問題 Hierarchical CSP

Borning[19]提出了限制條件階層化的概念,也就是說對於不同的限制條件 給予不同的階層。在 Hierarchical CSP 的求解過程當中,在滿足所有必要的硬 性條件之後,會依照軟性條件的階層不同,由最重要的限制條件優先進行處理,

相關文件