BOO入門/類別
定義類別
[編輯]類別很重要,因為這可以讓你將程式碼切割為一個或數個比較簡單、比較具邏輯的區塊,以便於作適當的組織和資料操作。
// 宣告類別
class Cat:
pass
fluffy = Cat()
上面的程式宣告了一個空的類別,名稱是 "Cat",裡面沒有任何的成員與方法。而 fluffy 則是 Cat 類別的實體。
欄位與屬性
[編輯]簡單的說,欄位持有資訊,而屬性則是存取資訊。
// 屬性範例
class Cat:
[Property(Name)]
_name as string
fluffy = Cat()
fluffy.Name = 'Fluffy'
- class Cat: 開始宣告類別
- [Property(Name)] 表示宣告一個屬性:Name,來源是 _name。
- _name as string 表示宣告 Cat 的欄位: _name,型態為字串。
- fluffy = Cat() 宣告一個 Cat 的實體。
- fluffy.Name = 'Fluffy' 存取 Cat 的屬性:Name,並設置為 'Fluffy'。實際上會使得 _name 被設為 'Fluffy'。
因為安全(封裝)的緣故,欄位通常不直接存取。
有另外兩種宣告 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 | 表示無法被繼承。 |
// 類別修飾詞範例
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。屬性必須明白地宣告在介面裡面。方法將會在下一章:方法解釋。
值與參考型別的相異處
[編輯]在 Boo/.NET 的世界裡,型別有兩種類型:值與參考。所有的類別都是參考型別。在值型別列表提到的數值、boolean、字元都是值型別。
值型別永遠不能被設為 null,永遠都有預設值。數值性別的預設值永遠是 0。
練習
[編輯]- 建立一個繼承多個介面的類別。
- 試試看繼承多個類別,看會發生什麼事情?
// 繼承範例
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