有一個重要的概念你需要弄明白,那就是 `Class`「類」和 `Object`「物件」的區別。問題在於,class 和 object 並沒有真正的不同。它們其實是同樣的東西,只是在不同的時間名字不同罷了。我用禪語來解釋一下吧:
`魚(Fish)和鮭魚(Salmon)有什麼區別?`
這個問題有沒有讓你有點暈呢?說真的,坐下來想一分鐘。我的意思是說,魚和鮭魚是不一樣,不過它們其實也是一樣的是不是?泥鰍是魚的一種,所以說沒什麼不同,不過泥鰍又有些特別,它和別的種類的魚的確不一樣,比如鮭魚和比目魚就不一樣。所以鮭魚和魚既相同又不同。怪了。
這個問題讓人暈的原因是大部分人不會這樣去思考問題,其實每個人都懂這一點,你無須去思考魚和鮭魚的區別,因為你知道它們之間的關係。你知道鮭魚是魚的一種,而且魚還有別的種類,根本就沒必要去思考這類問題。
讓我們更進一步,假設你有一隻水桶,裡邊有三條鮭魚。假設你的好人卡多到沒地方用,於是你給它們分別取名叫Frank,Joe,Mary。現在想想這個問題:
`Mary 和鮭魚有什麼區別?`
這個問題一樣的奇怪,但比起魚和鮭魚的問題來還好點。你知道 Mary是一條鮭魚,所以他並沒什麼不同,他只是鮭魚的一個「實例(instance)」。Joe 和Frank 一樣也是鮭魚的實例。我的意思是說,它們是由鮭魚創建出來的,而且代表著和鮭魚一樣的屬性。
所以我們的思維方式是(你可能會有點不習慣):魚是一個「類(class)」,鮭魚是一個「類(class)」,而 Mary 是一個「物件(object)」。仔細想想,然後我再一點一點慢慢解釋給你。
魚是一個「類」,表示它不是一個真正的東西,而是一個用來描述具有同類屬性的實例的概括性詞彙。你有鰭?你有鰾?你住在水裡?好吧那你就是一條魚。
後來一個博士路過,看到你的水桶,於是告訴你:「小伙子,你這些魚是鮭魚。」 專家一出,真相即現。並且專家還定義了一個新的叫做「鮭魚」的「類」,而這個「類」又有它特定的屬性。長鼻子?紅肉?體型大?住在海裡或是乾淨新鮮的水裡?吃起來味道不錯?那你就是一條鮭魚。
最後一個廚師過來了,他跟博士說:「非也非也,你看到的是鮭魚,我看到的是Mary,而且我要把 Mary 淋上美味醬料做一道小菜。 」於是你就有了一隻叫做Mary 的鮭魚的「實例(instance)」(鮭魚也是魚的一個「實例」),並且你使用了它(把它塞到你的胃裡了),這樣它就是一個「物件(object)」。
這會你應該了解了:Mary 是鮭魚的成員,而鮭魚又是魚的成員。這裡的關係式:物件屬於某個類,而某個類又屬於另一個類。
## 寫成程式碼是什麼樣子
這個概念有點詭異,不過實話說,你只要在建立和使用class的時候操心一下就可以了。我來給你兩個區分 `Class` 和 `Object`的小技巧。
首先針對類和物件,你需要學會兩個說法,「is-a(是啥)」和「has-a(有啥)」。「是啥」要用在談論「兩者以類的關係互相關聯」的時候,而「有啥」要用在「兩者無共同點,僅是互為參照」的時候。
接下來,通讀這段程式碼,將每一個註解為`##??`的位置標明他是「is-a」還是「has-a」的關係,並講明白這個關係是什麼。在程式碼的開始我還舉了幾個例子,所以你只要寫剩下的就可以了。
記住,「是啥」指的是魚和鮭魚的關係,而「有啥」指的是鮭魚和烤肉架的關係。
~~~
## Animal is-a object (yes, sort of confusing) look at the extra credit
class Animal
end
## ??
class Dog < Animal
def initialize(name)
## ??
@name = name
end
end
## ??
class Cat < Animal
def initialize(name)
## ??
@name = name
end
end
## ??
class Person
attr_accessor :pet
def initialize(name)
## ??
@name = name
## Person has-a pet of some kind
@pet = nil
end
end
## ??
class Employee < Person
def initialize(name, salary)
## ?? hmm what is this strange magic?
super(name)
## ??
@salary = salary
end
end
## ??
class Fish
end
## ??
class Salmon < Fish
end
## ??
class Halibut < Fish
end
## rover is-a Dog
rover = Dog.new("Rover")
## ??
satan = Cat.new("Satan")
## ??
mary = Person.new("Mary")
## ??
mary.pet = satan
## ??
frank = Employee.new("Frank", 120000)
## ??
frank.pet = rover
## ??
flipper = Fish.new
## ??
crouse = Salmon.new
## ??
harry = Halibut.new
~~~
## 加分習題
1. 有沒有辦法把 `Class` 當作 `Object` 使用呢?
2. 在習題中為 animals、fish、還有people 添加一些函式,讓它們做一些事情。看看當函數在 Animal 這樣的「基類(base class)」裡和在 Dog 裡有什麼區別。
3. 找些別人的程式碼,理清裡邊的「是啥」和「有啥」的關係。
4. 使用 Array 和 Hash 建立一些新的一對應多的「has-many」的關係。
5. 你認為會有一種「has-many」的關係嗎?閱讀一下關於「多重繼承(multiple inheritance)」的資料,然後儘量避免這種用法。
- 笨方法更简单
- 习题 0: 准备工作
- 习题 1: 第一个程式
- 习题 2: 注释和井号
- 习题 3: 数字和数学计算
- 习题 4: 变数(variable)和命名
- 习题 5: 更多的变数和印出
- 习题 6: 字串(string)和文字
- 习题 7: 更多印出
- 习题 8: 印出,印出
- 习题 9: 印出,印出,印出
- 习题 10: 那是什么?
- 习题 11: 提问
- 习题 12: 模组 (Module)
- 习题 13: 参数、解包、参数
- 习题 14: 提示和传递
- 习题 15: 读取档案
- 习题 16: 读写档案
- 习题 17: 更多的档案操作
- 习题 18: 命名、变数、程式码、函式
- 习题 19: 函式和变数
- 习题 20: 函式和档案
- 习题 21: 函式可以传回东西
- 习题 22: 到现在你学到了哪些东西?
- 习题 23: 阅读一些程式码
- 习题 24: 更多练习
- 习题 25: 更多更多的练习
- 习题 26: 恭喜你,现在来考试了!
- 习题 27: 记住逻辑关系
- 习题 28: 布林(Boolean)表示式练习
- 习题 29: 如果(if)
- 习题 30: Else 和 If
- 习题 31: 做出决定
- 习题 32: 回圈和阵列
- 习题 33: While 回圈
- 习题 34: 存取阵列里的元素
- 习题 35: 分支 (Branches) 和函式 (Functions)
- 习题 36: 设计和测试
- 习题 37: 复习各种符号
- 习题 38: 阅读程式码
- 习题 39: 阵列的操作
- 习题 40: Hash, 可爱的 Hash
- 习题 41: 来自 Percal 25 号行星的哥顿人(Gothons)
- 习题 42: 物以类聚
- 习题 43: 你来制作一个游戏
- 习题 44: 评估你的游戏
- 习题 45: 物件、类和从属关系
- 习题 46: 一个专案骨架
- 习题 47: 自动化测试
- 习题 48: 更进阶的使用者输入
- 习题 49: 创造句子
- 习题 50: 你的第一个网站
- 习题 51: 从浏览器中取得输入
- 习题 52: 创造你的网页游戏
- 下一步
- 一个老程式设计师的建议