漫談 物件導向概念 Object Oriented Concept             by 蔡神 tsaiwn@cs.nctu.edu.tw
    前 言 (關於 Flash AS3 與 Java 語言)
    物件導向概念(Object Oriented Concept)的四大特性
    物件 Object  vs.  類別 class
    Flash 的顯示物件(DisplayObject)類別
    關於 Java 事件監聽模式的用法
    事件(Event)是蝦密碗糕 ?(看完可以按視窗左上角的回到這裡)
    點這裡看Java命名慣例(看完可以按視窗左上角的回到這裡)
    Flash的實體名稱命名建議(看完可以按視窗左上角的回到這裡)
    完整變數與函數命名原則(看完可以按視窗左上角的回到這裡)
    程式設計超簡單(蔡神寫的程式設計簡介)(看完可以按視窗左上角的回到這裡)

    更多關於Java/C++使用物件與設計物件的概念
     關於設計物件的類別... 
前 言
Flash 的 ActionScript 3 (AS3) 是以 Java 語言為基礎, 採用物件導向(Object Oriented)的概念。
但 Flash 更有彈性, 以務實為原則, 不堅持難懂的理論, 先舉出其與 Java 語言最大的不同:
  (1)Flash 物件的屬性(Property; attribute)可以在創建物件之後任意添加(即動態增加), 
           這更貼近真實世界, 因為你昨天沒有鬍子並不代表今天沒有鬍子:-)
           Java語言則不可以在執行階段 (Rum time)動態增加物件的屬性。
  (2)Flash 註冊事件監聽器(Event Listener)的方法與Java語言不同!!
      Java 註冊時的參數只有一個, 是一個物件(Object), 該物件所屬的類別內有一個至很多個處理事件的函數!
           當然該多個處理事件函數各自處理不同事件, 但是是屬於相關的事件(合起來是某類, 例如滑鼠類的事件)
           也因為這樣, 註冊申請監聽的"命令"有一大堆 .addXXXListener( ) 函數,
           這裡的XXX 代表某類(class)事件, 例如想要註冊處理滑鼠類事件(MouseEvent),
           假設要監控的物件是 big_btn 這按鈕, 寫法是 big_btn.addMouseListener(有處理滑鼠事件之類別的實體);
     Flash 簡化了事件處理模式, 規定每次註冊只能針對一個事件, 且是指定處理函數!
           而且一招走遍天下, 只有一句註冊命令:  
             被監控物件.addEventListener(事件, 函數); 
           例如: 
             big_btn.addEventListener(MouseEvent.CLICK, her);  // big_btn 被滑鼠按一下則請 her(){} 處理
             funtciotn her(e: MouseEvent) {
                 trace(""+ e.target.name + " 被滑鼠按了一下"); // 印在開發時期主控台面板
                 //... 做事
             } // her(  
       這裡的函數 her( ) 平時不會做事, 只有在 big_btn 被滑鼠按一下才會動起來。
    因為註冊被簡化了, 如果你希望滑鼠滑入 big_btn 也要做事情, 那必須再註冊一次, 例如:
             big_btn.addEventListener(MouseEvent.MOUSE_OVER, you); 
    這裡的 you 與上面的 her 類似, 都是獨立函數(function; 函式; 又叫method方法), 如果你認為這樣
    太多個函數(請太多外勞或找來太多小弟?), 那也可把該滑鼠滑入的事件也註冊給 her( )一起處理 :
             big_btn.addEventListener(MouseEvent.MOUSE_OVER, her); 
        但是, 這樣一來你的 her( ) 必須要辨認到底是滑入(MOUSE_OVER)還是被按一下(MouseEvent.CLICK);
    這是真實世界能者多勞的概念, 一個人可以做很多事, 一個函數當然也可以做很多事, 通常是根據不同狀況做不同事,
    可以利用 if 測試條件或是利用switch case 敘述做更多的判斷; 還好, 這也很簡單, 因為系統會把事件(Event)傳入
    函數 her( ), 所以才要寫 function her(e: MouseEvent) { 這頭部, 小括號內就是系統傳過來
    的參數(parameter), 在her( )的程式碼中就可以從傳過來的 e 這事件找出需要的資訊, 包括 e.target 是發生此事件的物件, 
    因為 her( ) 這函數也可能被要求要同時要監控其它的按鈕(或其它物件)的某幾種事件。

       至於 Java 的事件監聽模式規範比較嚴謹, 對於初學者常搞不清楚, 但等你弄懂了卻又覺得它很有道理,
    如果你急著想知道更多關於 Java 事件監聽的用法, (或是原來學 Java 沒有很認真聽現在忽然想認真了解)
    可以點這跳到後面看Java 註冊事件監聽的用法(看完可以點視窗左上角的回到這)。

物件導向概念(Object Oriented Concept)

    物件導向(Object Oriented)主要是類比於實際世界的物件(Object),例如汽車是一種類別(Class),
房車與跑車都是一種汽車, 表示房車是汽車做了一些修改或擴充(extends)的新類別, 跑車也是汽車做了一些修改或擴充(extends),
所以房車和跑車都是繼承(inherits)自汽車的類別, 或說房車與跑車都是 extends 汽車, 都是從汽車擴充(extends)而來!
    物件(Object)有時與類別(Class)被混為一談, 例如某人說:"請幫我設計一個 ??? 的物件", 其實他的意思應該是
要說"請幫我設計一個 ??? 的類別(class)"才對, 關於物件與類別的討論稍後再說。

    請注意, 有些電腦語言雖然提供物件設計與使用概念, 但是不提供把已經寫好的物件類別"擴充"(extends, 即繼承inherits),
則該語言不是物件導向(Object Oriented), 只是以物件為基礎的語言(Object Based Language)。
真正的物件導向應該包括以下四大特性: 
  (1)封裝 Encapsulation: 把資料(data)與跟該些 data 有關的函數(function)或方法(method)封裝到一個類別(class)內
       這與真實世界很類似, 鬧鐘裡面有許多元件, 各元件有其功能(function; 沒錯, 功能的英文也是function),
       全部被封裝在一起變成一個產品, 只露出給我們看的以及給我們按的按鈕或旋鈕。
  (2)資訊隱藏 Information hiding(data hiding): 只有類別內的函數或方法可以存取物件內私密的資料(private data)
       這更是類比於真實世界, 想一想你要設定鬧鐘會把鬧鐘拆開用手去撥動其指針嗎? 你需要動到其內部的電子零件嗎? 
       所以設計物件的類別時有個重要原則: 資料(屬性)儘量藏起來(hide), 函數(功能)儘量公開讓外界使用!
       意思是資料儘量用 private 修飾語隱藏在內部, 只有內部的函數可以存取它,
       函數則儘量用 public 修飾語開放給外部直接使用, 所以鬧鐘外表有一些按鈕或旋鈕。
  (3)繼承 Inheritance 或 擴充 extends : 可以把舊的類別擴充成新的類別, 可增刪資料成員與函數成員
       這概念很重要, 所以等一下我們用"動物與植物都是生物!"來詳細解釋。
  (4)多型 Polymorphism : 以基底類別(base class)的指標(C++的pointer)或參考(reference)操作衍生類別(derived class)的物件
       這比較難理解, 假設 Dog 和 Cat 都是 Animal(動物)這類別的子類別, 通常所有的 Animal 都會叫,
       在這, "叫" 是一個函數, 如果 myObj 被宣告或定義為一個 Animal 物件, 
       那我們當然可以寫 myObj.叫( ); 表示 myObj 做"叫"的動作(action),
           問題來了, 我設計程式之時並不知道 myObj 會是 Dog 還是 Cat, 到時可能可能是 Dog 也可能是 Cat 甚至其他類別!
       一個支援多型(Polymorphism)的電腦語言會根據 myObj 是 Dog 還是  Cat 去執行正確的叫( );
       如果 myObj 是 Dog, 那 myObj.叫( ); 用到的是 Dog 裡面的叫( ); 如果是 Cat 當然用到的是 Cat 裡面的叫( );
       這在程式語言中的專業術語叫做動態綁定(dynamic binding; 動態繫結), 意思是在執行階段(Run time)才決定啦。
       而這個動態綁定函數的專業術語就是多型(Polymorphism)啦。

   不太懂? 沒關係, 因為這些議題已經超出我們課程的範圍, 該議題留給資工系的同學去傷腦筋即可 :-)

但是繼承(Inheritance) 或 擴充(extends)的概念很重要! 
所以我們現在用真實世界的概念來試著讓大家理解。
類別的繼承概念可以用我們小時候就學過的"界門綱目科屬種..."來作說明,
想起來了嗎?

動物與植物都是生物! 
    所以動物與植物都繼承了生物的特性, 但又各自添加了不一樣的屬性(資料)與方法(動作行為)。
然後, 動物界又分為42門, 不記得? 哈哈 .. 我也不記得:-)
人類是動物界的脊索動物門, 哺乳綱, 靈長目, 人科, 人屬, 人種;
老師是人, 學生也是人, 也就是說老師與學生都是從"人"擴充(extends)來的!
(雖然有一部電影叫做 "老師不是人")

    繼承(inherits)或擴充(extends)的概念非常重要, 例如已經有個類別叫做鬧鐘,
現在要設計豪華鬧鐘, 你該不會從 0 做起吧? 
英文有句話很有名: Do NOT re-invent the wheel !
意思是不必再重新發明輪子, 已經有人發明了你就拿來用! (嚴格說來把輪子拿來用並不是繼承, 只是使用)
    既然已經有鬧鐘, 顯然豪華鬧鐘也是鬧鐘,
所以我們只要把鬧鐘拿來"擴充"並略加修改(modify)即可:
     class 豪華鬧鐘  extends 鬧鐘  {
          // ... 添加或蓋掉某些原有的屬性或方法(函數)
     } // class 
 
也就是說, 只要有類似這種 YY 就是 GG  的關係(YY is a GG; 豪華鬧鐘 is a 鬧鐘), 
或者該說 YY 是 GG 的一種特例, 例如 豪華鬧鐘 是 鬧鐘 的一種特例; 既然 YY is_a GG,
則 可以把 GG 拿來擴充(extends)為 YY, 那麼在 Java 語言就可以寫成: 
     class YY extends GG {                                                    
        // 新增的屬性或欄位或說變數                                           
        // 新增的函數或說方法, 包括要把原來 GG 已有的函數蓋掉(Override)的新函數 
     }                                                                        
  這就是所謂的繼承(inherits)或是擴充(extends)的概念,
是物件導向四大概念中很重要的概念, 有了這概念, 節省了程式設計師很多的時間!

    所有的物件都是物件! 這是 Flash AS3 與 Java 語言的基本理念, 萬物都是"物件", 萬物皆源自"物件";
所以,在Flash 的 Action Script 3.0中,開天闢地第一個物件類別與 Java 語言相同, 都是一個叫做 Object 的類別,
因為所有的其他物件皆源自於它,也就是所有的物件類別都是從 Object 繼承下來的子子孫孫。 
  
  在該些子子孫孫當中, 有一個類別是可以顯示在畫面上的, 稱為可視物件(DisplayObject)或翻譯為可顯示物件,
急著想知道DisplayObject可顯示物件的可以點這跳到後面看(看完可以點視窗左上角的回到這)。

    最常用的影片片段(MovieClip)即是 flash.display.DisplayObject 類別(簡稱 DisplayObject)的子類別(subclass); 
也就是說, flash.display.MovieClip 類別是從 flash.display.DisplayObject 類別擴充(extends)而來的;
反過來說, DisplayObject 是 MovieClip 的父類別(super class); 當然你要翻譯為母類別也是可以啦:-) 
不要把 super class 翻譯為超級類別喔! 那樣很多人可能搞不清黑市蝦密碗糕, 還以為是超人的爸爸ㄟ。 
所以, 在 Flash 與 Java 我們可以說任何物件都是 Object (物件國語就是俗稱的"東西", 物件是台語, 發音如"麵件")

  Object → … → DisplayObject → MovieClip 
  Object → … → DisplayObject → Sprite  

在 Flash 的 AS3 程式中, 可以任意創建物件, 不必事先定義類別(class), 例如: 

     var aa={age:25, height:175};   
 
   這是將 aa 宣告成物件型態,
   此物件將帶著age、height的參數屬性(Property; attribute),Flash 物件的特性可以持續增加新的屬性(Java不可以喔!)。 
使用物件也很簡單,  例如以下句子(statement)應該一看就知其意義:   
   var  ww: Number = aa.height;
   aa.age  += 1;  // 加 1 到 aa.age 使其增加一歲 :-)  

還有, Flash 可以任意添加新的屬性:  
   aa.weight=75;
   aa.email= "somebody@gmail.com";  
 
這樣就自動多出了兩種屬性(property, attribute; 或稱之為 member data 成員資料)。

   以上我們首先創建一個 aa 物件,然後就可以不斷的擴充添加新的屬性,並且填入不同的值。 
這種寫法,原則上就是直接引用始祖物件 Object 類別的寫法。 
  
    Flash 也可以事先定義嚴謹型的類別,必須寫在外部 .as 檔案,嚴謹型類別事先規劃該類物件的屬性與方法,
之後使用者就只能讀取、設定到該些屬性,而無法再有其他的屬性值。 
當然你還是可以 extends 擴充該類別為新的類別,以便添加其他屬性與方法(method, 即函數 function)。
 
以下是物件導向的類別 NameCard 的範例,必須寫在獨立的 .as 檔案。
  
package {
 // package資料包,或稱套件; 為獨立命名空間 
public class NameCard extends Object {
    //宣告一個公用(public)別,稱之為 NameCard,繼承(Extends)開天闢地第一個 類別 Object 
  public function NameCard( ) {  // 建構子 Constructor
     //物件被創建( new ) 出來後立刻會做的事情要寫在這 
    super( );  //告訴繼承的類別(Object)訊息; 若括號內是空的可以不必寫!
  } 
   //////
  public age: int;
  //具備年齡的屬性 
  public height:Number;
  //具備身高的屬性 
  public wet:Number;   // weight 體重, 偷懶用 wet
  //具備體重的屬性 
    
 } // class
} // package  
 
 
再提醒: 
   類別(class)不能夠直接寫在影格上,必須寫在外部的. as 文件檔案中,與 Flash 的 .fla 檔案放同一個目錄。 

更多關於 ActionScript 的變數舉例說明可以點這連過去看(英文)(開新窗)


 Top
如何從程式碼中創建一個物件 ? 當我們已經寫好了一個類別之後,總是要把它放入我們的程式中。其寫法很簡單, 就像新增一般的物件一樣,例如: var bb: NameCard = new NameCard( ); // 注意這物件佔據記憶體, 但我們看不見

物件 Object  vs.  類別 class 

物以類聚,  所以物件是某種類別的一個案例(instance; 實體; 複製品分身), 以真實世界的說法, 設計了一個類別
等於是設計了該類物件的藍圖, 然後可以製造(create;創建)出很多份該藍圖的實體(instance;案例);
例如 MovieClip 影片片段是一個類別, 其全名是 flash.display.MovieClip, 我們可以寫:
     var gg : MovieClip;  
 這樣則 gg 就是一個物件 (Object), 是一個 MovieClip 這類的物件。 
咦 .. gg 不是一個變數(variable)嗎? 
對啦, gg 是變數, 也是物件, 也就是說物件其實是變數的一種。 
     var kk : int = 38; 
  通常這 kk 我們不說它是物件, 只說它是一個整數變數, (雖然你還是可以說 kk 是個整數物件:-)
因為這 kk 只有一個整數值, 沒有其他屬性(property)。

張三是一個人, 李四也是一個人, 他們都是"人" 類 的案例, 所以 人 是一個類別(class),
張三與李四則都是 人 的一個物件(Object)或是實體(Instance)。 

   var 張三: 人;
   var 李四: 人; 

    前面說過, 有時候物件和類別會被混為一談, 要從前後文(context)才能知道講話者的真正意思 :-)
請注意, 因為 Flash AS3 是以 Java 語言為基礎, 所以開天闢地第一個類別是名稱叫 Object 的類別。
請養成正確的命名慣例: 
   類別名稱第一個字母請用大寫! 
   物件名稱或變數名稱的第一個字母請用小寫!
 還有, Flash 的套件名稱 package name 有遵守 Java 慣例, 也是全部用小寫。
 其實 package name 是反應其目錄結構, 也就是說 flash.display.MovieClip 意思是 MovieClip 這類別是放在flash子目錄的dispaly子目錄內。



 Top
Flash 的顯示物件(DisplayObject)類別

現在我們來釐清一些重要概念!
對, 就是顯示物件(flash.display.DisplayObject)類別
     與
 顯示物件容器(flash.display.DisplayObjectContainer)類別的概念!
    (再次提醒, Flash AS3 採用 Java 語言慣例, 套件package名稱用小寫, 類別class名稱第一個字母大寫!)

參看  DisplayObject 顯示物件:
     http://help.adobe.com/zh_TW/FlashPlatform/reference/actionscript/3/flash/display/DisplayObject.html?filter_flash=cs5&filter_flashplayer=10.2&filter_air=2.6
   以及 DisplayObjectContainer 顯示物件容器:
         http://help.adobe.com/zh_TW/FlashPlatform/reference/actionscript/3/flash/display/DisplayObjectContainer.html

Flash 的 DisplayObject 在標準 Java 對應的是 java.awt.Component 類別, 點這看其 API (開新窗) 在 JavaMe 則是 Displayable, 點這看 Displayable 的類別說明(開新窗) 在 Google Android 則是android.view.View 類別, 點這看該 View 類別(開新窗) Flash 的 DisplayObjectContainer 在標準 Java 對應的是 java.awt.Container 類別, 點這看其 API (開新窗) 在 JavaMe 則沒有對應的類別 在 Google Android 則是android.view.ViewGroup 類別, 點這看該 ViewGroup 類別(開新窗)

重點概念: 顯示物件容器(DisplayObjectContainer)除了可以有自己的視覺化內容可呈現外, 還可以包含其他的顯示物件,做為自己的子物件, 就像容器內可放其他物件。 可利用的顯示物件容器類別常用的有以下類別(class): Stage 舞台; 代表主要繪圖區。 Stage 類別有四個祖系類別 (DisplayObjectContainer、InteractiveObject、 DisplayObject 和 EventDispatcher), MovieClip 影片片段; 與 Sprite 物件不同的是,MovieClip 物件擁有時間軸。 其實 MovieClip 類別是 Sprite 類別的子類別。 更正確說, MovieClip 類別會繼承下列五個類別: Sprite、DisplayObjectContainer、InteractiveObject、DisplayObject 與 EventDispatcher。 且 MovieClip 有六個子類別。 Loader 載入器;類別可用來載入 SWF 檔案或影像檔 (JPG、PNG 或 GIF)。 請使用 load() 方法來起始載入。 載入的顯示物件會當做 Loader 物件的子系加入。 Sprite 精靈圖(在畫面上會動的圖片稱為 Sprite) 這 Sprite 類別是基本的顯示清單建構區塊:可以顯示圖像, 也可以包含子系的顯示清單節點。 Sprite 物件與影片片段相似,但卻沒有時間軸。 針對不需要時間軸的物件而言,Sprite 是一個適當的基底類別。 目前ActionScript 3 版本的 Sprite 有十五個子類別, 前面說的 MovieClip 影片片段也是其中一個。 (蔡神註: ActionScript 遵守 Java 習慣, class 類別名稱第一個字母用大寫, 物件object名稱第一個字母小寫。) (所以 Stage 是類別, stage 是物件, 且是 Stage 類別的一個案例(instance)。) TextLine 這 TextLine 類別是用來顯示顯示清單上的文字。 但是, 您不能直接從 ActionScript 程式碼建立 TextLine 物件。 如果您呼叫 new TextLine(),就會擲出例外。 若要建立 TextLine 物件,請呼叫 TextBlock 的 createTextLine() 方法。 請參看以下影片片段物件結構圖: 有了這物件容器附屬關係的概念, 我們就可以利用顯示物件容器(DisplayObjectContainer)類別所提供的幾個方法(函數) 來做動態加入與移除物件到某個容器物件, 包括舞台(stage)以及主時間軸(root; 根部)等容器物件! 常用的函數(方法)如下: (soneObj 為某物件) someObj.addChild(物件 ); 可以將物件加入某個someObj容器物件(影片片段或舞台)並顯示。 此函數完整語法是 addChild(child:DisplayObject):DisplayObject someObj.addChildAt(物件, 堆疊層次編號); 此函數完整語法是 addChildAt(child:DisplayObject, index:int):DisplayObject someObj.removeChild(物件 ); 可以將物件從某個someObj容器物件中移除 此函數完整語法是 removeChild(child:DisplayObject):DisplayObject someObj.removeChild(堆疊層次編號); 可以將該編號物件從某個someObj容器物件中移除 此函數完整語法是 removeChildAt(index:int):DisplayObject 更多的資訊可以點這看Adobe網站
關於顯示物件類別(DisplayObject, 可視類別) 凡是從 DisplayObject 衍生(derived)或說擴充(extends)來的類別都屬於可顯示的物件! 以下是 Adobe AS3 關於顯示物件類別的繼承圖: 請注意,這些類別之中有一些並未包含在 flash.display 套件中, 但仍然是繼承自 DisplayObject 類別,尤其是 StaticText、TextField 和 Video。 擴充 DisplayObject 類別的所有類別也會同時繼承其方法和屬性。 你可以點這裡看關於 DisplayObject 類別的方法(method, 函數function)和屬性(property)。 關於以上這些核心顯示類別的更詳細說明請看 Adobe 官方網站: 關於核心顯示類別 http://help.adobe.com/zh_TW/as3/dev/WS5b3ccc516d4fbf351e63e3d118a9b90204-7e3c.html 。 關於 Flash ActionScript 3.0 開發人員指南, 請看這 http://help.adobe.com/zh_TW/as3/dev/index.html

 Top


關於 Java 事件監聽模式的用法

    Java 強調物件的概念, 函數(function) 不可以獨立存在(C和C++可以, Flash也可以), 必須靠行放在某個類別(class)裡面,
因此不允許直接把一個處理函數註冊給某個監聽事件! 
事實上 Java 的事件處理函數(Event handler)名稱是規定好的, 我們不能任意更改!
Java 規定 XXXEvent 的事件處理者所屬之類別必須實作(implemtnts) XXXListener 介面(Interface),
概略的說介面 (Interface)就是一個已經寫了一些空函數的類別, 該些空函數只規範了函數雛形(樣子), 其真正內容則必須
由實作該介面的類別內補寫(這時會寫 @Override 以告訴編譯器說該函數是重寫的)。
例如, 如果我們希望當使用者按了 big_btn 這按鈕要處理, 首先我們必須先寫一個有能力處理的類別(名稱自訂):
      class God implements MouseListener {
          // 共有五個函數要寫:mouseClicked(), mouseEntered(), mouseExited(), mousePressed(),mouseReleased()
          //以下這個是當滑鼠按一下會用的: (即 Flash 的 MouseEvent.CLICK 用的)
          public  void mouseClicked(MouseEvent e) {
             // 處理 滑鼠按一下 該做的事
          }
          // 其他四個 function, 即使不做事也要依照規定寫出空的函數
          //..
          // 如果你只想寫你需要的其他不寫, 那必須把implements MouseListener改為extends MouseAdapter

      } // class God 結束  

  然後你必須創建一個 God 的實體(instance), 可以有名稱也可以沒名稱, 把該實體註冊給 big_btn, 例如: 
      big_btn.addMouseListener(new God( ) );   // 無名氏物件(anonymous object)
       或是 
      God tmp = new God( );  // tmp 是一個臨時的王牌天神 God
      big_btn.addMouseListener( tmp );   // 有人按了(動到了) big_btn 則交給 tmp 去處理

如果你從程式碼打開一個視窗(Window), 假設視窗物件名稱是 abc, 你希望使用者按了該窗的右上角 X 可以關掉窗,
那你必須寫一個類別 implements WindowListener 以便有能力處理視窗事件(WindowEvent), 
然後用 abc.addWindowListener(該類別的實體物件);
大概的樣子如下:
      class Devil implements MouseListener {
          // 共有七個函數與 Window 事件也關要寫: windowClosing(WindowEvent e), windowIconified(WindowEvent e), ...
          //以下這個是當滑鼠按一下會用的: (即 Flash 的 MouseEvent.CLICK 用的)
          public  void windowClosing(WindowEvent e) {
             // 處理 滑鼠按一下視窗右上角的 X 要做的事, 可做任何事喔! 
             // 你現在知道何以很多色情網站的窗關不掉了吧?
             // .. 有些更狠, 你企圖關一個窗, 阿它給你另開三個窗ㄟ !  
          }
          // 其他六個 function, 即使不做事也要依照規定寫出空的函數
          //..
          // 如果你只想寫你需要的其他不寫, 那必須把implements WindowListener改為extends WindowAdapter

      } // class Devil 結束  
      Devil ggyy = new Devil( );
      abc.addWindowListener(ggyy);
      // 如果沒有另外寫 class Devil 而是把所有七個與 Window 事件有關的處理函數都寫在主類別內,
      // 則主類別自己必須 implements MouseListener
      // 且註冊要寫這樣:  abc.addWindowListener(this); 

初學者看到一大堆 .addXXXListener( ) 常常一個頭兩個大,
但是當你搞清楚原來 XXX 是有分門別類得很清楚, 要處理 XXX 事件(XXXEvent), 必須有 XXXListener 的能力,
也就是含有處理 XXX 事件函數的類別必須 implements XXXListener 才可以。
    然後, 如果你要監聽 abc 這物件, 必須用到正確的 .addXXXListener( );
且必須交給它(放在參數)一個有能力處理 XXX 事件的物件變數。
你把 XXX 換成 Mouse, 就是 MouseListener 會處理 MouseEvent;
把 XXX 換成 Window, 就是 WindowListener 會處理 WindowEvent;
以此類通, 這樣瞭了吧 ?


關於 MouseListener 請點這看Java API手冊(開新窗)

關於 WindowListener 請點這看Java API手冊(開新窗)


 Top

補充更多關於Java與 C++ 使用物件的概念

    有些同學仍不太了解"物件使用"的概念!
注意, 我現在只是說"使用"喔!  
例如,  System.out. 後面可以寫那些東東以及如何查還有人不知道 !?
現在我來補充如何使用"物件"! 包括 C++ 與 Java 的物件! 
  (要弄懂原理才不會忘掉!  不要只是想依賴像 Eclipse 這種工具!
    要思考如果是你要設計如 Eclipse 這類工具那要如何做? 
    阿就是說要學會釣魚, 不要只等著別人把魚給你吃! ) 

  物件的使用在 C++ 比較麻煩,
因為在 C++ 可以直接使用物件, 也可以透過指標使用物件:
    Dog x;   // x 佔據一大塊記憶體
    Dog *pp = new Dog( );  // pp 是指標, 指到一大塊記憶體!
注意現在是在說 C++ 喔!
假設 Dog 這 class 內有欄位 weight 代表狗重量,
有函數 bark( ); 代表會讓該隻狗把它的重量"叫"出來!例如:
    class Dog {    // C++ program
       private:  double weight; 
       public:
          double bark( ) { return weight; }
          Dog( ) { weight = 38.49; }
    }; // class  // 注意 C++ 這裡的分號; 不可省掉!       
這時, 在主程式中你可能想要寫 double yy = x.weight; 

表示想要取得 x 這隻狗的重量! 
但是, 若在 class Dog 內這 weight 是 private,
則此句想拿 x.weight 是錯的, 編譯不會過!
那如何取得 x 的重量呢? 
   很簡單, 剛不是說 bark( ) 會"叫"出(回傳)其重量!
阿通常這 bark( ); 不可以 private 阿不然就 class 外都不能用!
所以通常是 public 啦! 
因此我們可以寫 double yy = x.bark( ); 
   不過既然  bark( ) 是會傳回其重量的 function,
比較好的方式是改名為 getWeight( ); 所謂必也正名乎 :-)
這樣我們就可以用 double yy = x.getWeight( ); 

再來, 那對於指標 pp 該怎麼用呢?(注意現在是講C++) 
我們要取得 pp 指過去那狗的重量要怎辦? 
==> 要寫  yy = p->getWeight( );  // p-> 表示 p 指到的那物件
  (其實照原來想法要寫 p->.getWeight( ); 阿可是.. 
     ..這樣三個標點符號連在一起太醜了, 所以 C 設計者認為 -> 後面的點就不要了!)
  這樣, 似乎有點麻煩!? 可是用 C++ 就是要這樣啦! 
     (歹勢, 是 C 語言就規定指標要這樣用, C++ 只是蕭規曹隨沒改 !)
注意, 在這 C++ 例子, Dog x; 就已經有一塊記憶體放 Dog 狗的全部資料!
所以 x 是一個"物件", 且是完整物件! 
可是, 注意, Java 不是這樣! Java 為了簡化使用程序, 規定所有的物件只有一種存取方法! 阿就是 Java 規定所有的物件都要透過"參考"(reference); 請注意, 參考(reference)很像指標(pointer), 但不是指標! 事實上, Java 宣稱沒有指標, 意思是"夏威夷我們去就好" .. 阿不是, 我是說 Java 設計者認為指標讓Java設計者自己用就好(由編譯器自己偷用:-), 但是對 Java 程式而言看起來沒有指標; 因為在 C/C++ 語言, 指標(pointer)只是一個整數, 代表另一塊記憶體的起點, 可是這樣很容易搞錯, 尤其是初學者常被指標搞得昏頭轉向! 所以 Java 乾脆規定沒有指標, 且規定不可以像 C++"直接用物件", 所有的物件都須透過"參考"來使用, "參考"(Reference)是一種特殊的資料結構, 裡面除了記錄物件在何處, 也記錄了物件一些重要資訊, 例如如果該物件是一個陣列(Array), 它會偷記錄其長度(有幾個元素)。 所以, 在 Java 中寫 Dog x; 這樣 x 只是一個參考(reference), 這個"參考"很像 C++ 的指標, 但不是! 因為 C++ 的指標真的只是一個整數, 代表主記憶體的位置! 可是 Java 的參考(Reference)其實是個資料結構, 裡面當然要有個指標可以 指到"物件"所在的記憶體, 還會偷記住許多有用的相關資訊! 所以 Dog x; 之後還要 x = new Dog( ); 這樣才會安排一大塊記憶體以便 存放 x 這 Dog 的資料!(只有資料, 函數是另外放在別處的!) (如果 new 了很多 Dog 物件, 資料各自有一份, 但函數是共用一份!) 注意, 與 C++ 指標用法幾乎一樣, 但是因為 Java 的參考有偷記住許多資料, 因此可以在 Run time 知道那物件是啥碗糕! (這稱 Run time type checking), 但 C++ 在Run time(執行階段)是無法知道指標指過去的是蝦密碗糕!! Java這樣規定使得使用物件只有一個方式, 就是用"點"表示法 (dot notation) ! 例如, double yy = x.getWeight( ); 這樣也比較不會弄錯! 至於前面那個 C++ class Dog 在 Java 要稍作修改(文法略有差異): class Dog { // Java program private double weight; // 每項的存取控制都要獨立講! 所以不必用冒號: public double bark( ) { return weight; } public Dog( ) { weight = 38.49; } } // class
所以, 請注意, Java 的物件一定要 new 才會"長出"物件(安排記憶體), 否則只有該物件的"參考"(Reference)! (當然物件的參考也佔據一小塊記憶體) 假設已經知道 GgYy 是 Java 某個 package 內的一個 class, 我們看到程式中有句 GgYy.getTopic( ).???; 請問, 若不使用如 Eclipse 這類IDE工具, 怎要麼知道該 ??? 部分有哪些可以用呢? Ans: (1)看 API 網頁或是用 javap 找出 getTopic( )會回傳啥? 用 javap 必須知道 GgYy 是在哪個 package; 查看 API 網頁則可以用搜尋的找到! (2)知道 getTopic( )回傳的 type 後, 該 type 一定是個 class, 否則其後不可能再寫 .??? (3)再用 API網頁或是用 javap 查看該 type 的 class 裡面有哪些"attribute"可以用? 因為該 "???"後面沒有括號就表示 "???"是 data field, 若有括號則必是函數! 還有, 此例既然 GgYy 是 class, 則 getTopic( ) 一定是個 static 函數, 否則不能寫 GgYy.getTopic( )...
更多思考: 假如 GgYy 是不照慣例寫的某個物件變數呢? 回答如上同樣問題!
 

關於設計物件的類別 Design class

  以下來討論 "設計物件" ..
     更正確的說應該是 "設計物件的藍圖", 或說設計類別 (Class) ! 
因為物件一定是某個類別的一個案例(Instance;實體; 實例), 英文說:
       Object is an instance of some class. 
       "物件" 是某種類別的一個案例(Instance; 例子; 實體; 複製品)! 
    所以, 當我們說要設計物件, 其實意思是要設計某種 "類別" (class),
以便以後可以使用該類別的"物件"(Object),
阿物件(Object)就是一種變數(Variable), 需要用一塊記憶體! 
前面說過, Java 為了簡單易懂, 
規定物件要 new 才會"生出" (或說製造出; 就是安排一塊記憶體給物件!) 
    所以, 設計物件的類別(class)是為了以後要 new 出該類別的一個案例來用!
若沒有 new 則只可以使用 class 內的 static member (靜態成員) 
所謂的靜態成員可以是變數也可以是函數(function; 函式 );
注意這裡說的變數也可以是不准變的變數(寫 final 的變數, 阿就是常數啦)! 
    請記住, class 內就是兩種成員(member): 變數 和 函數; 
沒有寫 static 的一定要有物件才可以使用,
更正確的說, 是要透過某個物件才可使用 non-static 的成員!  
  請注意, 寫 static 的 資料成員(就是變數, 或稱欄位)意思是即使沒有任何
該類別的物件這些 static資料也有一份, 
但即使已經生出(new)很多該類別的物件, 該些寫 static 的資料還是只有一份, 
阿就是 static 資料是該類別的所有物件共用的啦! 大家看到的是同一份!
    但是, 函數(function)不管是否寫 static 都是只有一份!
寫了 static 的函數當然還是可以透過物件(Object)變數使用它們!!
可是即使沒有 new 任何物件也可以用 類別名稱.函數名稱(參數); 使用它們!
例如,  double x = Math.random( );   
這裡 Math 是 class; random( ) 是在 Math 類別內一個 static double 的函數!
    還有, System.out... 是因為 System 這 class 內有個 static 物件變數 out, 
當然查 API 後會發現該 out 的 type 是 java.util.PrintStream; 
根據 Java 的設計習慣, Stream 是以 byte 為單位; Reader與Writer以 char 為單位 !
用 Print帶頭的 Stream 或 Writer 是有提供 print/println/printf等函數的類別!

    至於函數, 除了 constructor (建構子) 不必也不可以指定型別(type)外,
所有的函數都必須指定要回傳之資料的型別! (建構子是名稱與 class 同名的函數)
成員函數若不會回傳資料則須寫 void 型別( void 原來意思是 "無效")!
型別可以是原始型別(Primitive type; 共有八種), 也可以是物件類別(class)! 
物件類別(class)可以是 Java 程式庫的, 也可以是我們自己設計的! 
    阿那我們要如何設計"類別"(class)呢? 
很簡單, 就是: 
    把資料以及與該些資料關的函數用 class  包起來,
使其自成一個程式單元(Program unit)!
    例如, 要設計一個堆疊(Stack), 先想好 Stack 要怎麼做?
有很多方法, 通常給我一個陣列(Array), 再給我一個整數可以代表指向該 Array,
再搭配一個 push(x)可把 x 推入, 一個 top( ) 可讀取堆疊頂端,
以及一個 pop( )  可以把堆疊頂端元素拉出拋棄, 這樣就是個 class Stack 了! 
    不過, Java 的 Stack 是拿 Vector 擴充(extends)來的!
那 Java 的 Vector 是啥呢? 就是個會在必要時自己長大的 Array 陣列 ! 

   設計物件時的原則是:
      o 把資料成員(data member)儘量藏起來(宣告 private 或 protectd),
      o 把函數成員(function member)儘量公開 (宣告 public)! 
請注意, Java 規定每個成員, 不管是資料還是函數,
都必須指出其存取控制權限, 如果 private, protected, public 三者都沒寫,
那屬於第四類: package available (同目錄內的 class 都可以直接用!)
    如果寫了 protected 者表示在自己 class 內可以直接用以外,
也可以在 extends 該類別的 class 內直接使用! 不管該子類別是放在哪個 package ! 
所謂 package 就是指相關的類別被放在同一個目錄之下, Java 的 package 名稱都用小寫 !
再來看看前面寫過的類別 Dog, 並寫更多函數在裡面: 
    class Dog {    // Java program
       private  double weight;    // 每項的存取控制都要獨立講! 所以不必用冒號:
       public  double getWeight( ) { return weight; }
       public  Dog( ) { weight = 38.49; }  // constructor 建構子
       public Dog(int x) { weight = x; }    // another 建構子
       public Dog(double x) { weight = x; }  // 又是另一個 Constructor
       public setWet(double x) { weight = x; }   // 改 weight
    } // class       



 Top
關於程式設計概念可看看這篇程式設計超簡單(開新窗)