Ruby 學習筆記-物件導向程式設計(OOP)

為什麼要有物件?

物件 = 狀態(名詞) + 行為(動詞)

透過物件導向程式設計,讓程式碼變得容易被理解與使用

物件-類別與實體

類別就像是一個模型,透過這個模型可以製造出許多實體以下方程式碼為例

    定義類別:
    class Lily
        def eat
            puts " 好吃!"
        end
    end

    產生實體:
    luna = Lily.new  #加上new就可以產生一個個實體
    luna.eat         #有實體就可以使用eat這個方法
    #luna是實體Lily是類別
  1. 類別的命名規定必須是常數常數必須要是大寫英文字母開頭
  2. 共同的特徵放在同一個分類(class)
    class Animal    #把狗與貓共同會有的方法定義在上一層
            def walk
            end
            def eat
            end
    end
    class Dog < Animal  #會繼承Animal裡的方法
    end
    class Cat < Animal  #會繼承Animal裡的方法
    end
    kitty = Cat.new    #kitty這個實體屬於貓類別
    kitty.eat          #因為貓類別繼承Animal所以他有eat這個方法

物件初始化-initialize

    class Lily
            def initialize      #特別的方法
                puts "hello!"
            end
    end
    kitty = Lily.new
    # hello!
    #不需要呼叫方法,按執行就會出現

    可使用參數
    class Lily
        def initialize(name,age)
            @name = name         #把 name 帶進 @name 實體變數上
            @age = age
        end
    end
    kitty = Lily.new("luna",18)  #luna與18會帶進上方的initialize方法參數(name,age)

new 是創造一個實體,initialize 是這個實體產生後的初始化方法

實體方法與類別方法

  1. 實體方法是作用在實體上的方法
        class Lily    #類別
            def eat
                puts "# 好吃!"
            end
        end
        luna = Lily.new
        luna.eat
        #luna是實體,eat作用在luna上所以是實體方法
    
  2. 類別方法是作用在類別上的方法

    在定義方法前,一定要在方法名稱前加上 self

        class Lily
            def self.eat       #一定要加上self
                puts " 好吃!"
            end
        end
        Lily.eat
        #Lily是類別,eat是作用在Lily上所以是類別方法
    

實體變數與類別變數

  1. 實體變數

    一個@開頭,會存活在每個獨立的實體內,在實體內可自由取用的變數

        class Lily
            def initialize(name)
               @name = name         #1.把 name 帶進 @name 實體變數上
            end
            def name             #getter
               reture @name
            end
            def neme=(new_name)  #setter
              @name = new_name
            end
        end
        kitty = Lily.new("luna")  #2.在kitty裡會有一個 @name的實體變數
        kitty.name                #3.呼叫name方法時會回傳 @name這個變數,無法直接像js一樣取用
        kitty.neam=("lily")       # lily
    

    以上圖為例,我先用 Lily 這個類別製造一個實體名叫 kitty,再用初始化這個方法將 name 帶進@name 變成實體變數,所以我 kitty 這個實體內有個@name 的實體變數,@name 只存活在 Lily 這個類別裡,所以我無法直接呼叫 name,只能透過 say 方法把@name 回傳回來。

    attr_reader/attr_writer/attr_accessor

    在 Ruby 裡沒有屬性,所以取個值變得很麻煩,也因此有了 attr_reader/attr_writer/attr_accessor 來協助,以下為例

        class Lily
                attr_reader   :name    #只要有這個就不用在創造一個方法來回傳
                attr_writer   :name    #只要有這個就不用創造一個方法來做 @name重新設定名字
                attr_accessor :name    #此方法等同與上述 2個方法
                def initialize(name)
                        @name = name
                end
        end
        kitty = Lily.new("luna")
        puts kitty.neme          #在這裡就可以顯示了
        kitty.name = "lily"       #在這裡可重新設定名字
    
  2. 類別變數

    @@開頭,在類別方法內可自由取用的變數

        class Lily
                @@counter = 0   #類別變數
    
                def initialize
                        @@counter += 1
                end
                def self.counter
                        return @@counter
                end
        end
        5.times {Lily.new}  #進行5次初始化
        p Lily.counter   # 一樣要先創造一個self.counter的類別方法,才可以使用類別變數
        # 5
    

開放類別

    class Lily
            def hell0
            end
    end
    class Lily
            def world
            end
    end
    kitty = Lily.new
    kitty.hello    #可執行
    kitty.world    #可執行

在 Ruby 裡兩個同名的類別不會覆蓋而是融合,也因為開放的關係我可以幫現有的類別加功能,甚至內建類別也做得到。類別裡的方法則不是這樣,方法同名會覆蓋。

類別裡方法存取控制

封裝:有些方法不想讓外部使用只想內部使用,所以有了 public/private/protected
    class Lily
           def eat             #沒有明講就是public
           end
           private           #不讓外部使用
           def gossip
           end
    end
    kitty = Lily.new
    kitty.eat      #外部可使用
    kitty.gossip   #因方法設定在private下,所以外部無法使用

private:不能有明確的訊息接收者,意思是可以透過別的方法來存取此方法,以下為例

    class Lily
           def eat
               gossip
           end
           private
           def gossip
           end
    end
    kitty = Lily.new
    kitty.eat  #private不能有明確接收者,所以存取gossip方法,先要將他放進public方法裡,才可存取

private 與 protected 差在,在 public 的方法裡 protected 可以在方法前加 self,以下為例

    class Lily
           def eat
              self.gossip
           end
           protected
           def gossip
           end
    end
    kitty = Lily.new
    kitty.eat #protected不論有沒有self都存取得到,但private不可以
comments powered by Disqus