「カプセル化」とは
- 「利用者に関係のないものは見せない」という、オブジェクト指向言語の概念の一つ
- この概念により、下記のような安全性と利便性を確保できる
- 利用者に使ってほしい機能を安全に公開できる
- その機能を実現するための内部的で、直接利用者には利用してほしくない機能を隠蔽できる
- この概念により、下記のような安全性と利便性を確保できる
「カプセル化」の例
ここでは、C#を用いてカプセル化の例を紹介する。
悪いカプセル化の例
class Person
{
public string firstName; // 名
public string lastName; // 姓
public int age; // 年齢
public double height; // 身長
public double weight; // 体重
public string GetFullName()
{
return this.firstName + this.lastName;
}
}
上記のPersonクラスでは、以下に挙げる三点の理由から、カプセル化の利点を享受することができない。
-
フィールドの読み書きを、詳細に制御することができない
- 「フィールドの読込は認めたいが、書換は制限したい」という場面が、開発をしている最中に出てくるが、フィールドのアクセスレベルはアクセス修飾子でしか定義できないため、上記のような読込と書込で、アクセスレベルを分けることができない(
readonly
修飾子を用いることもできるが、クラス内部でも書換不可となるため、利便性が落ちる)
- 「フィールドの読込は認めたいが、書換は制限したい」という場面が、開発をしている最中に出てくるが、フィールドのアクセスレベルはアクセス修飾子でしか定義できないため、上記のような読込と書込で、アクセスレベルを分けることができない(
-
値の妥当性を検査できない
-
age
フィールドには年齢が入るので自然数が入るべきだが、自然数の型は存在しないので、負の整数を代入を制限することができず、不正データを生みやすくなってしまう
-
-
内部変更に弱い
- フィールドの値の持ち方、つまり型が変更された場合に改修箇所が増える
- 例えば、
height
/weight
フィールドがdouble
型らint
型に変更された場合、両フィールドを利用している全てのコードに影響が及ぶ
良いカプセル化の例
class Person
{
private string _firstName { get; set; } // 名
private string _lastName { get; set; } // 姓
private int _age; // 年齢
private double _height { get; set; } // 身長
private double _weight { get; set; } // 体重
public int Age
{
set
{
if (value < 0)
{
throw new ArgumentException("自然数を指定してください");
}
this._age = value;
}
get { return this._age; }
}
public string GetFullName()
{
return this.FirstName + this.LastName;
}
}
C#が用意している、フィールドを取得する仕組みである「プロパティ」を用いることで、クラス内ではメソッドのように表記できるが、クラス外からはフィールドのようにアクセスすることができる。
また、フィールドのアクセスレベルをprivate
にすることで、利用者側の不用意なアクセスを禁止している。
さらに、先述の悪い例で挙げた問題点を解決することができる。
-
読み書きを制御することができる
-
get
/set
キーワードには、個別にアクセス修飾子を付与できるので、詳細なアクセス制御が容易に実現できる - 但し、プロパティ自体のアクセスレベルを超えて設定はできない
-
-
値の妥当性を検査できる
-
age
フィールドに負の整数が入らないよう、代入前に検査を実装することができる
-
まとめ
このように、カプセル化においては、
- 機能の制限
- 外部で参照する際のインターフェイス
以上の二点を適切に設けることで、利用者が複雑な内部処理を意識することなく機能を使えるだけでなく、不用意に内部機能にアクセスすることを防ぐことができる。