ruby 基础知识 - Class 与 Module

原文

1. 因為 Ruby 並沒有「屬性」(property/attribute)這樣的設計,要取用實體變數,需要另外定義的方法才行:

class Cat
    def initialize(name, gender)
      @name = name
      @gender = gender
    end

    def name
      @name
    end

    def name=(new_name)
      @name = new_name
    end
end

改写 => 使用 attr_readerattr_writer 以及 attr_accessor 定义「讀取」、「設定」以及「讀取 + 設定」的方法,所以原來的有點囉嗦的寫法就可使用 attr_accessor 

class Cat
    attr_accessor :name

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

  

 2. 定义类方法

class Cat
    def self.all
      # ...
    end
end

  或者

class Cat
    class << self
      def all
        # ...
      end
    end
end

  

 3. 方法的存取控制

注意: initialize 方法,它永遠是 private 的,只會被 new 方法调用。

一般使用

class Cat
    def eat
      puts "好吃!"
    end

    protected
    def sleeping
      puts "zzzzzzzzz..."
    end

    private
    def gossip
      puts "我跟你說,你不要跟別人說喔!"
    end
end

另一種的方法存取限制是寫在方法定義之後

class Cat
    def eat
      puts "好吃!"
    end

    def sleeping
      puts "zzzzzzzzz..."
    end

    def gossip
      puts "我跟你說,你不要跟別人說喔!"
    end

    protected :sleeping
    private :gossip
end

 

使用说明:

1)其實 publicprotected 以及 private 這三個在 Ruby 裡並不是關鍵字,它只是一般的方法而已。

2)private 方法没有调用者 recevier,前面不可以有小数点。

在 Ruby 的 private 方法其實不只類別自己內部可以存取,它的子類別也可以,並沒有像其它程式語言一樣的繼承限制。

比如:

puts "Hello Ruby"

self.puts "Hello Ruby"  # NoMethodError

3) protected 方法,從外部來看,它跟 private 一樣,不能直接使用。

但在類別內部,它的規定就沒那麼嚴格了,你要指定或不指定 recevier 都可以。

4)private 其实也可以在外部调用

class Cat
    def say_hello
      self.gossip
    end

    private
    def gossip
      puts "我跟你說,你不要跟別人說喔!"
    end
end

kitty = Cat.new
kitty.gossip          # => NoMethodError
kitty.send(:gossip)   # => 我跟你說,你不要跟別人說喔!

咦?不是說呼叫 private 方法的時候不能有明確的接收者嗎?你仔細看,並沒有違反這個規定喔,這邊我是執行 send 方法,把 gossip 當做參數傳給它而已,所以不算違反規定。

 

4. 开放类别 Open Class

class Cat
    def abc
      # ...
    end
  end

  class Cat
    def xyz
      # ...
    end
  end

kitty = Cat.new
kitty.abc       # => 會發生什麼事?
kitty.xyz       # => 會發生什麼事?

1)两个相同的类会进行融合。

上面的两个类会变成这样

class Cat
    def abc
      # ...
    end

    def xyz
      # ...
    end
  end

除此之外,还可以对内建的类别进行融合

class String
    def say_hello
      "hi, I am #{self}"
    end
  end
puts "eddie".say_hello  # => hi, I am eddie
puts "kitty".say_hello  # => hi, I am kitty

2)Open Class 覆盖原来的方法。

class Integer
    def +(n)
      1000
    end
  end

  puts 1 + 2   #=> 得到 1000
  puts 3 + 4   #=> 得到 1000

改写

class Integer
    alias :original_plus :+

    def +(n)
      puts "hey hey hey"
      original_plus(n)
    end
  end

  puts 1 + 2
  puts 3 + 4

这里使用了 Ruby 內建的 alias 方法把原本的 + 方法加個別名 original_plus,然後再新定義的 + 方法裡,再呼叫它原本的算法。執行之後就會發現計算結果跟原本的 + 是一樣的,但會偷偷多印了 hey hey hey 字樣在畫面上。

 

5. 模组

定义一个模组

module Flyable
    def fly
      puts "I can fly!"
    end
  end

引入模组

class Cat
    include Flyable
  end

  kitty = Cat.new
  kitty.fly        # => I can fly!

Ruby 中 Include, Extend, Load, Require 的使用区别

 

「類別」的上層類別就是「模組」,開 IRB 實驗一下:

$ irb
>> Class.superclass
=> Module

区别

$ irb
>> Class.instance_methods - Module.instance_methods
=> [:new, :allocate, :superclass]

可以發現身為「後代」的 Class 類別,比 Module 類別多了 3 個方法,就是因為 Module 類別少了這 3 個方法,所以它跟 Class 最大的差別,就是:

  1. 模組沒辦法 new 一個新的實體出來。
  2. 模組沒辦法繼承別的模組。

除此之外,模組跟類別在本質上沒什麼太大的差別。

末尾!

posted on 2018-02-28 15:20  Lemo_wd  阅读(197)  评论(0编辑  收藏  举报

导航