ソフトウェアシステムにおいて、カプセル化とは、データと、そのデータを操作するメカニズムやメソッドをバンドルすることを指します。また、オブジェクトのコンポーネントなど、そのデータの一部への直接アクセスを制限することを指す場合もあります。[ 1 ]基本的に、カプセル化は、外部コードがオブジェクトの内部動作に関心を持つことを防ぎます。
カプセル化によって、開発者は内部実装に依存しない一貫性のあるインターフェースを提供できます。例えば、カプセル化は、構造化データオブジェクトの値や状態をクラス内に隠蔽するために使用できます。これにより、クライアントがこの情報に直接アクセスして、隠蔽された実装の詳細を露呈したり、メソッドによって維持される状態不変性を侵害したりすることを防ぎます。
カプセル化は、プログラマーが特定のデータセットに関連するすべてのコードを同じクラスにまとめることを促し、他のプログラマーが理解しやすいようにコードを整理します。カプセル化は、疎結合を促進する手法です。
オブジェクト指向プログラミング(OOP)システムはすべてカプセル化をサポートしていますが、 [ 2 ] [ 3 ]カプセル化はOOPに固有のものではありません。抽象データ型、モジュール、ライブラリの実装もカプセル化を提供します。この類似性は、プログラミング言語理論家によって存在型の観点から説明されています。[ 4 ]
オブジェクト指向プログラミング言語やその他の関連分野では、 カプセル化は、関連しているが異なる2つの概念のいずれか、またはそれらの組み合わせを指すことがあります。[ 5 ] [ 6 ]
プログラミング言語の研究者や学者の中には、最初の意味を単独で、あるいは2番目の意味と組み合わせて、オブジェクト指向プログラミングの特徴として用いる者もいる。一方、字句的クロージャを提供するプログラミング言語の中には、カプセル化をオブジェクト指向とは直交する言語の特徴とみなすものもある。
2つ目の定義は、多くのオブジェクト指向言語やその他の関連分野では、コンポーネントが自動的に隠蔽されるわけではなく、これを上書きできることを反映している。したがって、2つ目の定義を好む人々は、情報隠蔽を独立した概念として定義している。
カプセル化の機能は、ほとんどのオブジェクト指向言語においてクラスを用いてサポートされているが、他の代替手段も存在する。
カプセル化とは、反復的または複雑な処理を単一の呼び出し単位にまとめることを指す場合もある。オブジェクト指向プログラミングは、メソッドレベルとクラスレベルの両方でこれを可能にする。この定義は手続き型プログラミングにも適用できる。[ 10 ]
『デザインパターン』の著者は、継承とカプセル化の間の緊張関係について詳しく論じ、彼らの経験では、設計者は継承を使いすぎていると述べています。彼らは、継承によってサブクラスが親クラスの実装の詳細に晒されるため、継承はカプセル化を破ることが多いと主張しています。[ 11 ]ヨーヨー問題で説明されているように、継承、ひいてはカプセル化の使いすぎは、複雑になりすぎてデバッグが難しくなる可能性があります。
カプセル化は「データメンバーとメンバー関数を隠蔽するために使用できる」という定義に基づくと、オブジェクトの内部表現は一般的にオブジェクト定義の外部に隠蔽されます。通常、オブジェクト自身のメソッドのみが、そのフィールドを直接検査または操作できます。オブジェクトの内部を隠蔽することで、ユーザーがコンポーネントの内部データを無効または矛盾した状態に設定することを防ぎ、オブジェクトの整合性を保護します。カプセル化の利点として、開発者がソフトウェアコンポーネント間の相互依存関係を制限できるため、システムの複雑さを軽減し、堅牢性を高めることができるとされています。
SmalltalkやRubyのような一部の言語ではオブジェクトメソッドによるアクセスしか許可されていませんが、他のほとんどの言語(C++、C#、Delphi、Java [ 12 ]publicなど)では、通常、やなどのキーワードを使用して、隠蔽する内容をプログラマーが制御できますprivate。[ 8 ]protected ISO C++標準では、、privateおよびpublicを「アクセス指定子」と呼び、「情報を隠蔽しない」と述べています。情報の隠蔽は、ヘッダーファイルを介してインターフェースされるソースコードのコンパイル済みバージョンを提供することによって実現されます。
ほとんどの場合、このような保護を無効化する方法が存在します。通常はリフレクションAPI(Ruby、Java、C#など)を介して、場合によっては名前マングリング(Python)のようなメカニズム、あるいはC++のような特殊なキーワードの使用によって無効化されますfriend。オブジェクトレベルの機能ベースのセキュリティ(オブジェクト機能モデルに準拠)を提供するシステムは例外であり、強力なカプセル化を保証します。
C++、C#、Java、[ 12 ] PHP、Swift、Delphiなどの言語は、データフィールドへのアクセスを制限する方法を提供します。
![]()
以下は、キーワードを使用してデータフィールドへのアクセスを制限する方法を示すC#の例ですprivate。
class Program { public class Account { private decimal _accountBalance = 500.00m ;public decimal CheckBalance () { return _accountBalance ; } }static void Main () { Account myAccount = new (); decimal myBalance = myAccount . CheckBalance (); /* この Main メソッドは、Account クラスが提供するパブリックな * "CheckBalance" メソッドを使用して残高を確認できます が、 * "accountBalance" の値を操作することはできません。 */ } }以下はJavaの例です。
public class Employee { private BigDecimal salary = new BigDecimal ( 50000.00 ); public BigDecimal getSalary () { return this . salary ; }public static void main () { Employee e = new Employee (); BigDecimal sal = e.getSalary ( ) ; } }オブジェクト指向言語以外でもカプセル化は可能です。例えば、 C言語では、APIのクライアントがキーワードを使ってアクセスできないデータメンバーを含むデータ項目を操作する一連の関数のヘッダーファイルを介して、パブリックAPIで構造体を宣言できますextern。[ 13 ]
// ヘッダーファイル "api.h" #pragma oncetypedef struct Entity Entity ; // 隠しメンバーを持つ不透明な構造体// 'Entity' オブジェクトを操作する API 関数Entity * openEntity ( int id ); int processEntity ( Entity * e ); void closeEntity ( Entity * e );クライアントは、不透明なデータ型のオブジェクトを割り当て、操作し、解放するために、API 関数を呼び出します。この型の内容は、API 関数の実装のみが認識し、アクセスできます。クライアントは、その内容に直接アクセスすることはできません。これらの関数のソースコードには、構造体の実際の内容が定義されています。
// 実装ファイル "api.c"#include "api.h"typedef struct Entity { int ent_id ; // ID 番号char ent_name [ 20 ]; // 名前...およびその他のメンバー... } Entity ;// API関数の実装Entity * openEntity ( int id ) { // ... }int processEntity ( Entity * e ) { // ... }void closeEntity ( Entity * e ) { // ... }以下は変数アクセス制限をサポートしていないPythonの例です。ただし、アンダースコアで始まる名前の変数はプライベートとみなされるのが慣例です。[ 14 ]
class Car : def __init__ ( self ) -> None : self . _maxspeed = 200def drive ( self ) -> None : print ( f "最大速度は{ self._maxspeed }です。" )redcar : Car = Car () redcar . drive () # これは「最高速度は 200 です」と出力します。redcar._maxspeed = 10 redcar.drive () # これは「最大速度は10です」と出力します。カプセル化メカニズムにより、プログラマはデータと、それらを操作するサブルーチンを1か所にまとめてグループ化し、抽象化のユーザーから無関係な詳細を隠すことができます。