物件導向的特色
物件 = 狀態(n.) + 行為(v.)
- 以class建置一個物件,接著def類別的狀態,然後建立一個實體。 ```ruby= class Dog
def bark puts “汪 !” end
end
=> bark
- class 及 end 中間的程式碼,即是類別。
這個範圍中,使用了bark這個方法,並對應於該類別物件的狀態與行為。
# 類別(Class)
- 使用類別產生實體
- 命名規則必須是"常數"
```ruby=
class Dog
def bark
puts "汪 !"
end
end
=> bark
Dog為類別的名稱
def … end 定義狀態與行為
在一個Dog類別裡,使用bark方法,定義其狀態,並執行
汪!
行為類別方法(self)
- 使用
self
方法,並以.
連接後方的狀態 > 要直接印出“類別”的行為時,要使用self給予後方的狀態作定義,才可執行行為 ```ruby= class Dog def self.say_hello puts “早安 , 我是小黑!” endend
Dog.say_hello
=> 早安 , 我是小黑! ```
最後將類別連接方法(狀態)say_hello,即可印出行為。
初始化(initialize)
- 建立初始化物件的方法,意即雖然沒有定義給類別任何的”狀態”,但因為是初始化(即出生就會做的事),這時只要直接將類別搭配
new
方法,即可印出。
class Human
def initialize
puts "hi , 早安"
end
end
Human.new
=> hi , 早安
new與initialize的關係
- 先new後再initialize
- 而在new方法的引數,後續會由initialize方法的參數收下,並傳至給內部的實體變數
@
class Person
def initialize(name , age)
@name = name
@age = age
end
def greeting
puts "hi 我是#{@name},今年#{@age}"
end
end
man = Person.new("abc" , 18)
man.greeting
=> hi 我是abc , 今年18
new後方帶入引數
initialize後方的參數接收
傳至initialize內部的實體變數@
類別變數(@@username)
- 在類別方法裡可以取用的變數 > 1. 在Dog類別裡,有一個類別變數@@count,並將其指定為0
- 使用了initialize方法,一樣使用類別變數@@count並指定其為+= 1(每次以1作為遞增)
而因為@@count在類別裡是共用的,所以只要Dog類別裡被new出實體,則@@count每次都會以1做增加(new與initialize為因果關係)
self在這意即:將Dog本身做count方法
class Dog @@count = 0 def initialize @@count += 1 end def self.count @@count end end 5.times{ Dog.new } p Dog.count => 5
3.接著要將Dog類別new出5次,並執行,但是要先在類別方法裡才可以取用@@count。
4.使用self方法並連接count狀態,一樣使用@@count類別變數,即可順利執行。
開放類別(open class)
- 當有兩個同名的類別撞再一起時,並不會互相覆蓋,而是會”結合”。
- rail裡大量使用了開放類別技巧
- rail = 在web方面特化版的ruby ```ruby= class Fruit def apple puts “an apple” end end
class Fruit def banana puts “a banana” end end
word = Fruit.new word.apple word.banana
=> an apple => a banana
> 1.定義了兩個同名的Fruit類別,裡面各別使用apple與banana方法。
> 2.建立實體word,並分別印出。
> 3.程式碼並不會發生錯誤。
- 透過開放類別,可以幫現有的類別加功能,甚至內建的類別也做得到。
```ruby=
class String
def say_hello
"hi , This is an #{self}"
end
end
puts "apple".say_hello
puts "umbrella".say_hello
This is an apple
This is an umbrella
1.使用了
String
類別,並且在裡面定義了say_hello方法,根據開放類別的定義:當兩個同名的類別撞在一起時,”方法”並不會被覆蓋,而是會結合,所以在那之後所有的字串都會有say_hello方法可用。2.say_hello方法裡使用self方法當變數(使用self可直接call出類別的方法)。
3.再將字串直接加上say_hello方法即可印出。
實體(instance)
- 屬於該類別的物件,即為實體。 ```ruby= class Dog
def bark puts “早安,我是小黑!” end
end lucky = Dog.new lucky.bark
=> 早安,我是小黑! ```
因為類別會產生實體,所以建立Dog類別後,使用new,並產生lucky”實體“,有了lucky實體後,加上定義的狀態(bark),便可執行行為”早安,我是小黑!”
實體方法
- 同上,此處作用在實體lucky的bark方法,即稱為實體方法。
實體變數(@username)
- 所有的實體變數預設值都是:nil ```ruby= @x
=> nil
- 在"實體外"取用時,則要再定義一個方法getter(讀取 / 取用)
```ruby=
class Dog
def initialize(name)
@name = name
end
def name
return @name
end
end
lucky = Dog.new("我是小黑!")
puts lucky.name
=> 我是小黑!
同前例,如果要在實體外”以name變數直接執行”時,則需要重新定義方法”name”,此舉稱為:getter。
attr_reader = getter (讀取)
- 使用attr_reader,後方並接符號參數,即可取代原getter的指令串,使程式碼更簡潔。
class Dog
attr_reader :name
def initialize(name)
@name = name
end
end
lucky = Dog.new("我是小黑 !")
puts lucky.name
=> 我是小黑!
- 重新定義一個方法為name=,並帶入參數(new_name),方法裡一樣放入實體變數@name並將其指定為new_name,即可印出,而此舉稱為setter。
class Dog
def initialize(name)
@name = name
end
def name
@name
end
def name=(name_2)
@name = name_2
end
end
lucky = Dog.new("我是小黑!")
puts lucky.name
lucky.name = "goofy" #1
lucky.name="goofy" #2
lucky.name=("goofy") #3
=> 我是小黑!
=> goofy
如果要將name的結果指定為goofy,會出現”name=“未被定義,而這裡常使用的#1程式碼其實=#2也=#3,因為在ruby裡()可以適時被省略,而使方法name看起來像屬性,但ruby語言裡並沒有”屬性“,在這裡的name=即是方法。
attr_writer = setter (設定)
- 使用attr_writer,後方並接符號參數,即可取代原setter的指令串,使程式碼更簡潔。
class Dog
attr_writer :name
def initialize(name)
@name = name
end
def name
@name
end
lucky = Dog.new("我是小黑!")
puts lucky.name
lucky.name = "goofy"
lucky.name="goofy"
lucky.name=("goofy")
puts lucky.name
=> 我是小黑!
=> goofy
attr_accessor :name (讀取+設定)
class Lion
attr_accessor :name
def initialize(name)
@name = name
end
end
kitty = Lion.new("獅子王!")
puts kitty.name
kitty.name = "這次不是獅子王!"
puts kitty.name
=> 獅子王!
=> 這次不是獅子王!
繼承(inherit)
- 與其說是繼承,不如說是分類。
class Pets
def walk(sunshine)
puts "漫步於...#{sunshine}"
end
def eat(food)
puts "滿滿的...#{food}"
end
end
class Dog < Pets
end
class Cat < Pets
end
Dog.new.walk("雲端")
Dog.new.eat("肉")
Cat.new.eat"罐頭"
Cat.new.walk("深山")
=> 漫步於...雲端
=> 滿滿的...肉
=> 滿滿的...罐頭
=> 漫步於...深山
1.建立了Pets類別,並def了walk與eat方法
2.建立名為Dog與Cat的類別,並繼承自上一層的Pets 以
<
表示,這樣一來,就算Dog與Cat類別空空的都沒寫,也一樣會有walk與eat的方法可用3.將Dog與Cat類別以new方法,並以
.
接上Pets裡的類別方法,與引數(引數的小括號可適時省略)