存取修飾子

2003 年 5 月 13 日

物件導向語言將程式區分為稱為類別的模組。每個類別包含功能,由資料 (欄位) 和方法組成。(並非所有語言都使用這些術語,但它們適用於此。) 語言有各種規則,說明其他類別可以如何存取類別的功能,這些規則通常基於套用於類別的存取修飾子。

C++ 選擇

最有影響力的存取修飾子組可能始於 C++,它有三個。

  • public:任何類別都可以存取功能
  • protected:任何子類別都可以存取功能
  • private:沒有其他類別可以存取功能

類別也可以使用 friend 關鍵字授予另一個類別或方法存取權限 - 因此 C++ 中的 friend 可以觸摸彼此的私密部分。

Java

Java 以 C++ 為基礎。它在語言中增加了套件的概念,這影響了行為。

  • public:任何類別
  • (package):(預設,且在程式碼中不使用關鍵字) 同一套件中的任何類別
  • protected:任何子類別或同一套件中的類別
  • private:沒有其他類別

請注意 Java 的 protected 和 C++ 的 protected 之間的細微差別 (只是為了讓事情混亂)。

C#

C# 也基於 C++ 模型

  • public:任何類別
  • internal:同一組件中的任何類別(方法和類別的預設,但可以指定)
  • protected:任何子類別
  • protected internal:任何子類別或同一組件中的類別
  • private:沒有其他類別(欄位的預設)

在 C# 中,組件是組成的實體單位 - 等同於 dll、jar 或二進位檔。C# 也有邏輯單位 (命名空間),類似於 java 套件,但它們不會在存取修飾子中發揮作用。

Smalltalk

Smalltalk 通常被認為是最純粹的 OO 語言,並且早於 C++、Java 和 C#。它不使用關鍵字來控制存取,而是使用基本政策。Smalltalker 會說欄位是私有的,而方法是公開的。

然而,私有欄位並不像它們在基於 C++ 的語言中的意思。在 C++ 語言中,存取被視為文字範圍。考慮一個範例,其中類別 Programmer 是類別 Person 的子類別,有兩個實例:Martin 和 Kent。在 C++ 中,由於兩個實例都屬於同一個類別,因此 Martin 可以存取 Kent 的私有功能。在 Smalltalk 的世界觀中,存取是基於物件的,因此由於 Martin 和 Kent 是不同的物件,因此 Martin 無權取得 Kent 的欄位。但同樣地,由於所有內容都是基於物件的,因此 Martin 可以取得他所有的欄位,即使它們是在 Person 類別中宣告的。因此,Smalltalk 中的資料比私有資料更接近受保護的資料,儘管物件範圍在任何情況下都會讓事情有所不同。

存取控制無法控制存取

如果有一個欄位是私密的,表示沒有其他類別可以取得它。錯!如果你真的想要,你幾乎可以在任何語言中顛覆存取控制機制。通常的方法是透過反射。其理由是,偵錯程式和其他系統工具通常需要看到私有資料,因此反射介面通常允許你這麼做。

C++ 沒有這種反射,但你可以直接使用記憶體處理,因為 C++ 本質上是開放式記憶體。

存取控制的重點不在於防止存取,而是傳達類別偏好將某些事情保留給自己。使用存取修飾詞,就像程式設計中的許多事情一樣,主要是為了溝通。

已發佈的方法

我認為確實有空間容納另一種存取類型:PublishedInterface。我認為,你向專案團隊中的其他類別公開的功能,與你向其他團隊(例如在 API 中)公開的功能之間存在著根本差異。這些已發佈的功能是公開功能的子集,必須以不同的方式處理,因此我相信已發佈與公開之間的區別比公開與私有之間的區別更為重要。