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