0%

類別與實體方法

類別(Class)與實體(Instance)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
class Lakers #類別
def self.all #類別方法
puts "defense!"
end
def shoot(shots) #實體方法
puts "nails a #{shots}!"
end
end

Lakers.all #呼叫類別方法

KCP = Lakers.new #Lakers_player為類別,KCP為實體
KCP.shoot "three-pointer"

#類別方法印出 defense!
#實體方法印出 nails a three-pointer!!

類別有繼承特性

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
class Animal
def eat(foods)
puts "#{foods} 超好吃!"
end
end

class Cat < Animal #繼承Animal,也可說是分類在Animal下面
end

Amy = Cat.new
Amy.eat "小魚乾" #印出小魚乾 超好吃!

class Dog < Animal #繼承Animal,也可說是分類在Animal下面
end

Ryan = Dog.new
Ryan.eat "潔牙骨" #印出潔牙骨 超好吃!

物件初始化

實體會先吃到初始化的指令

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
class Lakers_player
def initialize
puts "let's go Lakers!"
end

def shoot(shots)
puts "makes a #{shots}!"
end
end

Davis = Lakers_player.new
Davis.shoot "10 foot jumpshot"

# 印出let's go Lakers!
# makes a 10 foot jumpshot!

實體變數(Instance Variable)

寫法為 @ 開頭的變數,可在實體中裡自由取用,而且每個實體之間互不相影響。在使用 new 方法製作實體的時候,也可以順便傳參數進去。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
class Lakers
def initialize(name, position)
@name = name
@position = position
end

def introduction
puts "Hi, my name is #{@name}, I play #{@position}."
end
end

Lebron = Lakers.new("Lebron", "Small Forward")
Lebron.introduction

#印出 Hi, my name is Lebron, I play Small Forward.

取用實體變數的方法:

Ruby 的實體變數沒辦法直接從外部取用,否則會發生錯誤訊息:

1
2
3
4
Lebron = Lakers.new("Lebron", "Small Forward")
Lebron.position = "Center"

#undefined method `position=' for #<Lakers:0x00005648e0e018c8> (NoMethodError)

必須要將”.position=”這個方法先定義進去,才能取用

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
class Lakers
def initialize(position)
@position = position
end

def position
return @position #return可省略,會回傳@position,這三行稱之getter
end

def position=(new_position) #會設定我們下的參數,稱之setter
@position = new_position
end

end

Lebron = Lakers.new("Small Forward")
Lebron.position = "Center" #原始寫法為 position=("Center"),“position=”是一個方法,後面的center是參數
puts Lebron.position

#印出Center

Ruby 有幫我們定義了三個方法來解決這件事,分別是 attr_reader、attr_writer 以及 attr_accessor。這三個方法分別會做出「讀取」、「設定」以及「讀取 + 設定」的方法,所以原來的有點囉嗦的寫法就可使用 attr_accessor 改寫成這樣:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
class Lakers
attr_accessor :position

def initialize(name, position)
@name = name
@position = position
end

def introduction
puts "Hi, my name is #{@name}, I play #{@position}."
end
end

Lebron = Lakers.new("Lebron", "Small Forward")
Lebron.position = "Center"
puts Lebron.introduction

#印出Hi, my name is Lebron, I play Center.

類別變數(Class Variable)

隨著類別活著

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
class Dog
@@count = 0 #類別變數

def initialize
@@count += 1 #x += y => x = x + y
end

def self.counter #類別方法
return @@count
end
end

5.times { Dog.new }
p Dog.counter

#印出5

開放類別(Open Class)

如果同時出現多個相同名字的類別,在ruby的世界裡面,並不會由後面的覆蓋掉前面的,而是相互融合。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
class Lakers
def hi
puts "hi"
end
end

class Lakers
def yo
puts "yo"
end
end

Lebron = Lakers.new
Lebron.yo #印出yo
Lebron.hi #印出hi

ruby甚至可以改原本預設的類別,如string, integer..等

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
class Integer
def +(n)
100
end
end

p 1 + 2 #原始寫法是1物件呼叫+方法帶入2這個參數 p 1.+(2),印出100

class String
def say_hi
puts "hello #{self}!"
end
end

puts "Phil".say_hi #印出 hello Phil!

方法的存取控制

類別的方法存取限制常見的主要有三種:public、protected 以及 private。

  • public: 一般沒有特別註明就是public,所有的人都可以直接存取。
  • private: 在類別內部才可以存取。
  • protected(非常少用): 差不多是在這兩者之間,比 private 寬鬆一些,但又沒有 public 那麼自在,protected 在同一個類別內或是同一個 package,或是繼承它的子類別可以自由取用,但如果不是的話則不可存取。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
class Human
def walk #public
puts "一天一萬步 醫生遠離我"
end

private
def eat
puts "yumyum"
end

protected
def sleep
puts "Zzz"
end
end

Phil = Human.new
Phil.walk #印出一天一萬步 醫生遠離我
Phil.eat #NoMethodError
Phil.sleep #NoMethodError

Phil.eat這段code,在ruby的世界裡,指的是發送了eat這個訊息(message)給Phil這個接收者(receiver),而Private用法的規定,就是不能有接收者,也就是前面不能有小數點符號。

也有一些方法可以繞過這個規定,只要把eat這個方法當作參數傳回去即可從外部呼叫這個方法:

1
2
3
Phil.send (:eat) #印出yumyum

#可動態執行方法