跳至內容

BOO入門/類別

維基教科書,自由的教學讀本

BOO入門 > 類別 (上一章:函數 下一章:方法)


定義 定義 類別:一個聚合的包裝,包含了特定種類的編譯時期元數據。類別描述了物件如何呈現的規則,裏面除了定義資料結構之外,也定義了存取/操作資料的方法(函式)。
定義 定義 物件: 類別的實體。

定義類別

[編輯]

類別很重要,因為這可以讓你將程式碼切割為一個或數個比較簡單、比較具邏輯的區塊,以便於作適當的組織和資料操作。

// 宣告類別
class Cat:
    pass
fluffy = Cat()

上面的程式宣告了一個空的類別,名稱是 "Cat",裏面沒有任何的成員與方法。而 fluffy 則是 Cat 類別的實體。

建議 建議 所有類別名稱都應該使用 PascalCase,PascalCase 的意思是,將每個單字的第一個字母大寫並且不要使用空白。如果是縮寫的話,像 "URL",則用 "Url"。

欄位與屬性

[編輯]
定義 定義 欄位:類別裏包含特定資訊術語的元素。
定義 定義 屬性:用來取代 getter/setter 函數的語法。

簡單的說,欄位持有資訊,而屬性則是存取資訊。

// 屬性範例
class Cat:
    [Property(Name)]
    _name as string

fluffy = Cat()
fluffy.Name = 'Fluffy'
  1. class Cat: 開始宣告類別
    1. [Property(Name)] 表示宣告一個屬性:Name,來源是 _name。
    2. _name as string 表示宣告 Cat 的欄位: _name,型態為字串。
  2. fluffy = Cat() 宣告一個 Cat 的實體。
  3. fluffy.Name = 'Fluffy' 存取 Cat 的屬性:Name,並設置為 'Fluffy'。實際上會使得 _name 被設為 'Fluffy'。

因為安全(封裝)的緣故,欄位通常不直接存取。

建議 建議 使用 PascalCase 來命名屬性,就像命名類別一樣。使用底線為首的 CamelCase 來命名屬性。(CamelCase 類似 PascalCase,差別在於第一個字母為小寫。)

有另外兩種宣告 Property 的 Attribute:getter 與 setter。技術上來說,[Property] 就等同於 getter 加上 setter。

class Cat:
    [Getter(Name)]
    _name = 'Meowster'

    [Setter(FavoriteFood)]
    _favoriteFood as string

fluffy = Cat()
print fluffy.Name
fluffy.FavoriteFood = 'Broccoli'

輸出結果

Meowster

如果你試着指派值給 fluffy.Name 或是讀取 fluffy.FavoriteFood,將會發生錯誤,因為並沒有 Name 的 setter 與 FavoriteFood 的 getter。

使用 Property、Getter、Setter 這三個 attribute 非常方便,但只有 Boo 才能使用。當然,如果你比較熟悉 C#/VB.Net 的話,你也可以採取這樣的寫法:

// 明確的屬性範例
class Cat:
    Name as string:
        get:
            return _name
        set:
            _name = value

    _name as string

fluffy = Cat()
fluffy.Name = 'Fluffy'

因為欄位只有類別裏的方法、屬性能使用,你可以看到 Name 只是將 _name 包裹起來而已。將來如果你要加上額外的檢查或處理,只需要在 getter/setter 上加代碼就行了。

value 是 setter 述句裏的特殊關鍵字,它包含了指派的值。

屬性的預先條件判別

[編輯]

你可以在 Property attribute 裏面指定檢查條件式,而這條件式會發生在指派值之前,看看下面的例子:

// 屬性範例
class Cat:
    [Property(Name, Name is not null)]
    _name as string

fluffy = Cat()
fluffy.Name = null // 這行將會導致 boo 擲出引數錯誤的異常

類別修飾詞

[編輯]
修飾詞 描述
public 建立一個正常、公開的類別,可以被其他型別完整存取。
protected 表示類別只能被它所包含的類別(宣告在類別裏的類別)與繼承此類別的類別存取。
internal 只能在宣告的組件內使用。
protected internal 結合 protected 與 internal
private 表示類別只能被它所包含的類別(宣告在類別裏的類別)存取。
abstract 表示無法被實體化,通常作為其他類別的基底類別。
final 表示無法被繼承。
建議 建議 永遠都別用 public 修飾詞,因為當你沒有指定時,預設就是 public。
// 類別修飾詞範例
abstract class Cat:
    [Property(Name)]
    _name as string

abstract 關鍵字就是類別修飾詞之一,用法就是放在 class 的前面。

繼承

[編輯]
定義 定義 繼承:可以讓新類別享有既有類別實作與成員的方法,這可以讓你能盡可能地重複使用既有的代碼(當然,也許可能得視情況作一些修改。

在 Boo 裏,繼承非常簡單。

// 繼承範例
class Cat(Feline):
    [Property(Name)]
    _name as string

class Feline:
    [Property(Weight)]
    _weight as single //In Kilograms

上面的代碼讓 Cat 類別繼承 Feline,所以雖然 Cat 並沒有宣告 Weight 與 _weight,但 Cat 類別同樣有了 Weight 與 _weight 這兩個成員。 你可以讓多個類別繼承自同個類別,這可以達到代碼的可重用性。

更多關於繼承的東西,含括在[[第十章:多型與繼承裏面。

類別可以繼承自零或一個其他的類別,或是繼承自任意數目的介面。

如果要繼承多個介面,你應該使用這樣的語法:Child(IBaseOne, IBaseTwo, IBaseThree),至於介面,下一節會介紹。

介面

[編輯]
定義 定義 介面:介面定義了一組方法,讓類別能實作這些方法。對外界來說,只需要知道此介面,就可以使用介面裏定義的方法進行操作。

介面讓你可以設置給類別使用的 API,在定義的時候,並不會有程式碼的實作在裏面,真正的實作都會在繼承此介面的類別裏面。介面可以繼承多個介面,但不能繼承類別。

// 介面範例
interface IFeline:
    def Roar()

    Name:
        get:
        set:

範例裏面定義了介面 IFeline,裏面有一個方法:Roar 和一個屬性:Name。屬性必須明白地宣告在介面裏面。方法將會在下一章:方法解釋。

建議 建議 使用 PascalCase,並加上大寫 I 來命名你的介面,例如:IFeline。

值與參考型別的相異處

[編輯]

在 Boo/.NET 的世界裏,型別有兩種類型:值與參考。所有的類別都是參考型別。在值型別列表提到的數值、boolean、字元都是值型別。

定義 定義 null:用來表示參考型別變數未定義值的情形。

值型別永遠不能被設為 null,永遠都有預設值。數值性別的預設值永遠是 0。

練習

[編輯]
  1. 建立一個繼承多個介面的類別。
  2. 試試看繼承多個類別,看會發生什麼事情?

// 繼承範例

class Cat(Feline,Love):

   [Property(Name)]
   _name as string

class Feline:

   [Property(Weight)]
   _weight as single //In Kilograms

class love:

   [Property(Love)]
   _love as string

參考

[編輯]