Ruby 三大可見性關鍵字
| 關鍵字 | 調用限制 | 典型場景 |
public | 任意上下文可調用(預設) | 對外 API、業務入口 |
protected | 同類/子類實例間可互相調用(需顯式接收者) | 對象間協作、比較邏輯 |
private | 僅隱式調用(self. 禁止),繼承鏈可見 | 內部實現細節、工具方法 |
代碼實戰演示
class AccessDemo
def public_method
"public: #{private_method}" # 隱式調用 private 合法
end
def call_private_on(other)
other.private_method # 錯誤!顯式接收者調用 private 禁止
end
def call_protected_on(other)
other.protected_method # 合法!同類實例間可調用 protected
end
protected
def protected_method; "protected" end
private
def private_method; "private" end
end
# 驗證
obj1 = AccessDemo.new
obj2 = AccessDemo.new
puts obj1.public_method # => "public: private"
puts obj1.call_protected_on(obj2) # => "protected"
# obj1.call_private_on(obj2) # => NoMethodError: private method `private_method' called
核心規則圖解
┌─────────────────────────────────────────────────────────────┐
│ 可見性矩陣 │
├──────────────┬──────────────┬──────────────┬────────────────┤
│ 調用位置 │ public │ protected │ private │
├──────────────┼──────────────┼──────────────┼────────────────┤
│ 類外部 │ ✓ │ ✗ │ ✗ │
│ 類內部 │ ✓ │ ✓ │ 隱式調用 ✓ │
│ 子類內部 │ ✓ │ ✓ │ 隱式調用 ✓ │
│ 同類其他實例│ ✓ │ 顯式接收者 ✓ │ ✗ │
└──────────────┴──────────────┴──────────────┴────────────────┘
進階用法
- 動態修改可見性:
class Foo
def bar; end
end
Foo.send(:private, :bar) # 運行時將 bar 設為 private
- 模組混入時的可見性:
include 的模組方法默認 public,可用 private_class_method 等調整
- 頂層物件 main 的 private:腳本頂層定義的方法屬於
Object 的 private 實例方法
與 Java/C++ 對比
| 語言 | private | protected |
| Ruby | 僅隱式調用,繼承可見 | 同類/子類實例間可顯式調用 |
| Java | 同類可見,繼承不可見 | 同包+子類可見 |
| C++ | 同類/友元可見 | 同類/子類/友元可見 |
最佳實踐建議
- 默認 private:只暴露必要的 public API,降低耦合
- 內部協作用 protected:如
==、compare_to 需訪問另一實例內部狀態
- 避免濫用
send(:private_method):破壞封裝,僅測試/元編程慎用
- 文檔標註:YARD/RDoc 中用
@private 標記隱藏文檔
總結
Ruby 的可見性機制以 「隱式調用」為核心界限:private 禁止顯式接收者,protected 允許同類實例間顯式協作。這種設計鼓勵「告訴,不要詢問」的面向對象風格,同時保留了靈活的運行時修改能力。掌握三者邊界,是寫出優雅 Ruby 代碼的關鍵。