漫談 物件導向概念 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
關於程式設計概念可看看這篇程式設計超簡單(開新窗)