介面
介面是方法宣告的集合,可讓不相關的物件彼此互相通訊。例如,ActionScript 3.0 可以定義 IEventDispatcher 介面,其中包含類別可用來處理事件物件的方法宣告;IEventDispatcher 介面會為物件建立標準方式,以便彼此互相傳遞事件物件。下列程式碼會示範 IEventDispatcher 介面的定義:
public interface IEventDispatcher
{
function addEventListener(type:String, listener:Function,
useCapture:Boolean=false, priority:int=0,
useWeakReference:Boolean = false):void;
function removeEventListener(type:String, listener:Function,
useCapture:Boolean=false):void;
function dispatchEvent(event:Event):Boolean;
function hasEventListener(type:String):Boolean;
function willTrigger(type:String):Boolean;
}
介面是根據方法的介面及其實作之間的區別而來。方法的介面包含叫用該方法的所有必要資訊,包括方法的名稱、其所有參數,以及其傳回類型;方法的實作則不僅包括介面資訊,更包括可執行的陳述式以實踐方法的行為。介面定義則只包含方法介面,以及實作介面的任何類別,此類別負責定義方法實作。
在 ActionScript 3.0 中,EventDispatcher 類別會透過定義所有 IEventDispatcher 介面的方法,並將方法主體加入各方法中以實作 IEventDispatcher 介面。下列程式碼摘錄自 EventDispatcher 類別定義:
public class EventDispatcher implements IEventDispatcher
{
function dispatchEvent(event:Event):Boolean
{
/* implementation statements */
}
...
}
IEventDispatcher 介面為通訊協定,供 EventDispatcher 實體用來處理事件物件,並將它們傳遞給也是實作 IEventDispatcher 介面的其它物件。
另一種描述介面的方式是:介面可以像類別一樣定義資料類型。也就是說像類別一樣,介面可做為類型附註。做為資料類型的介面也可以搭配需要資料類型的運算子 (例如 is 和 as 運算子) 一起使用;但是跟類別不同的是,介面不能實體化。這項區別讓很多程式設計人員將介面視為抽象資料類型,而將類別視為具體資料類型。
定義介面
介面定義的結構類似於類別定義,只不過介面只能包含沒有方法主體的方法。介面不能包含變數或常數,但可以包含 getter 和 setter。若要定義介面,請使用 interface 關鍵字。例如,下列 IExternalizable 介面是 ActionScript 3.0 中 flash.utils 套件的一部分。IExternalizable 介面會定義序列化物件的通訊協定,也就是說,將物件轉換成適合儲存在裝置上或進行跨網路傳輸的格式。
public interface IExternalizable
{
function writeExternal(output:IDataOutput):void;
function readExternal(input:IDataInput):void;
}
IExternalizable 介面是以 public 存取控制修飾詞宣告。介面定義僅能由 public 和 internal 存取控制指定字加以修飾。介面定義之內的方法宣告不能有任何存取控制指定字。
ActionScript 3.0 遵循介面名稱以大寫 I 開頭的慣例,但您可以使用任何合法識別名稱做為介面名稱。介面定義經常是放在套件最上層。介面定義不能放在類別定義或其它介面定義之中。
介面可以擴充一個或多個其它介面。例如,下列介面 IExample 會擴充 IExternalizable 介面:
public interface IExample extends IExternalizable
{
function extra():void;
}
任何實作 IExample 介面的類別都必須包含 extra() 方法,以及繼承自 IExternalizable 介面的 writeExternal() 和 readExternal() 方法之實作。
在類別中實作介面
類別是 ActionScript 3.0 中唯一能夠實作介面的語言元素,在類別宣告中使用 implements 關鍵字,便能實作一個或多個介面。下列範例會定義兩個介面,IAlpha 和 IBeta,以及一個實作這兩個介面的類別 Alpha:
interface IAlpha
{
function foo(str:String):String;
}
interface IBeta
{
function bar():void;
}
class Alpha implements IAlpha, IBeta
{
public function foo(param:String):String {}
public function bar():void {}
}
在實作介面的類別中,實作方法時必須具備下列條件:
但是對於所實作方法參數的命名方式,還是有一些彈性。雖然已實作方法中的參數數目和各參數的資料類型都必須與介面方法相符,但是參數名稱並不需要相符。例如,在上一個範例中,Alpha.foo() 方法的參數就命名為 param:
但是,在 IAlpha.foo() 介面方法中,參數是命名為 str:
function foo(str:String):String;
在預設參數值上,也有一些彈性。介面定義可以包含有預設參數值的函數宣告。實作這種函數宣告之方法的預設參數值必須與介面定義中所指定值具有相同的資料類型,但實際值並不需要相同。例如,下列程式碼會定義包含具有預設參數值 3 之方法的介面:
interface IGamma
{
function doSomething(param:int = 3):void;
}
下列類別定義會實作 IGamma 介面,但使用不同的預設參數值:
class Gamma implements IGamma
{
public function doSomething(param:int = 4):void {}
}
具有這種彈性的原因在於:實作介面的規則是特別為確保資料類型相容性而設計的,因而需要完全相同的參數名稱,但預設參數值並不需要達到相同的目標。