物件導向的特色

物件 = 狀態(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 “早安 , 我是小黑!” end

end

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
  1. new後方帶入引數

  2. initialize後方的參數接收

  3. 傳至initialize內部的實體變數@

類別變數(@@username)

  • 在類別方法裡可以取用的變數 > 1. 在Dog類別裡,有一個類別變數@@count,並將其指定為0
  1. 使用了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裡的類別方法,與引數(引數的小括號可適時省略)