作成日 2007/5/5
最終更新日 2010/9/11
カプセル化と属性と操作
ここでは、カプセル化について説明します。
あ、その前に、クラスとオブジェクトについていまいち理解していない人は「
クラスとオブジェクト」を読んでください。
カプセル化と何か?、カプセル化すると具体的に何が良いのか?について説明します。
カプセル化はオブジェクト指向の3大要素のうちの1つです。
他には継承と多態性がありますが、それらよりもはるかに大事(保守性、可読性につながる)と思っています。
とりあえず、e-Words
からの引用で我慢して
オブジェクト指向プログラミングが持つ特徴の一つ。データとそれを操作する手続きを一体化して「オブジェクト」として定義し、オブジェクト内の細かい仕様や構造を外部から隠蔽すること。外部からは公開された手続きを利用することでしかデータを操作できないようにすることで、個々のオブジェクトの独立性が高まる。カプセル化を進めることによりオブジェクト内部の仕様変更が外部に影響しなくなり、ソフトウェアの保守性や開発効率が高まり、プログラムの部分的な再利用が容易になる。
e-Words カプセル化【encapsulation】より
すまん。
よくわからなかった…。
オブジェクト指向はDOAが元になっているということを、めちゃくちゃいい加減にだけど、「POA、DOAとオブジェクト指向 3.POA、DOAとオブジェクト指向」で説明した。
まず、データを設定するときにカプセル化したときとしなかったときのソース例をみて、何が良いのか考えてみよう。
言語はVBAとします。
カプセル化をしない場合
(クラスモジュール名:Class1)
|
カプセル化をした場合
(クラスモジュール名:Class2)
|
Public number as Integer |
Private m_number As Integer
Public Property Get number() As Integer
number =
m_number
End Property
Public Property Let number(ByVal newNumber As
Integer) m_number =
newNumber
End
Property |
じゃあ、これを使う場合は、
Class1を使うサンプル |
Class2を使うサンプル |
Sub main()
Dim obj As
Class1
Set obj = New Class1
obj.number = 1000
Debug.Print obj.number
End
Sub |
Sub main()
Dim obj As
Class2
Set obj = New Class2
obj.number = 1000
Debug.Print obj.number
End
Sub |
となる。
…って同じじゃないかって。
カプセル化って意味ないのかって?
そうです。単にデータを取得するアクセスメソッド(VBAではProperty
Getプロシージャ)とデータを設定するアクセスメソッド(VBAではProperty Let、Property
Setプロシージャ)を作っただけではカプセル化なんてほとんど意味ない感じがします。
じゃあ、こんど、クラスのnumber属性には0から100までの値しか入れたくない(例えば、テストの点数なんかそうです)場合を考えてみよう。
カプセル化をしない場合
(クラスモジュール名:Class3)
|
カプセル化をした場合
(クラスモジュール名:Class4)
|
Public number as Integer |
Private m_number As Integer
Public Property Get number() As Integer
number =
m_number
End Property
Public Property Let number(ByVal newNumber As Integer)
If (newNumber < 0) Or
(newNumber > 100) Then
Call Err.Raise(380)
End
If m_number =
newNumber
End
Property |
じゃあ、これを使う場合は、
Class3を使うサンプル |
Class4を使うサンプル |
Sub main()
Dim obj As
Class3
Set obj = New Class3
obj.number = 1000
Debug.Print obj.number
End
Sub |
Sub main()
Dim obj As
Class4
Set obj = New Class4
obj.number = 1000
Debug.Print obj.number
End
Sub |
となる。
…って、あれ、Class3を使うサンプルの方だけど、これだとnumberに1000という値が入っちゃうよ。
ということはこれを防ぐためにどこかで値のチェックをする必要が出てくるけど、それはどこでやる?
例えば、numberに値を設定する箇所すべてで値のチェックをしたら、もし、numberを使用している箇所が1000箇所もあったら、大変だ。(すべてに値のチェック処理を追加しないといけないし、漏れがあったら大変だ。)
あと、他にも、例えば、2つのデータを一緒に変更しないと駄目なものがあったり、あるデータ(例えばステータス)が特定の値になったときだけ、有効な値を持つことができるデータを定義したい場合はやっぱり、カプセル化しないと厳しいです。(カプセル化しないとデータの不整合が起こりやすくなります。)
一部繰り返しになりますが、カプセル化するメリットとしては、以下のようなものがあると思います。
-
データを設定するときにチェックできるので、不整合が起こりにくくすることが出来る(※1)。
スレッドセーフ
対応を行うことも可能になる。
- 2つ以上のデータを一緒に更新しないと駄目な場合、片方だけ更新しちゃったということが防げる。
- 設定されたときや取得されたときにログ出力するようなコードを書くことが出来るようになる。
- アクセス制御できる。
- VBAではできませんが、設定はコンストラクタからのみできるようにして、データ取得用のアクセスメソッドだけ作るようなことが出来る(※2)。
- 設定用と取得用のアクセスメソッドで可視性を別にする(VBAではできないけど、設定用のアクセスメソッドの可視性をProtected
にし、取得用の可視性をPublicにする)ということが出来る。
- データ構造の変更に対して多少強くなる。後で、データ構造やクラス構成が変わっても、メソッドでデータ構造が抽象化されているので、メソッドを使用している側のクラスの修正が少なくてすむ(※3)。
- データ設定時に呼び出し側が意識する必要の無い処理を設定メソッド内でさせるようにすることで、呼び出し側の凝集度の低下を防ぐことができる(※4)。
※1:データチェックはデータに関連する機能であると考えると、同じクラスにデータとデータチェック処理があるということはモジュールの強度(凝集度)が高くなるということだと思う。
※2:
イミュータブル(immutable)オブジェクト
を作れる。
※3:モジュールの結合度が低くなる気がする。
※4:どういう意味かと言うと、例えば、java.util.Vectorクラスではデータの追加時に、容量が足りなかったときに自動で領域を増やすということをする。
このような処理は、呼び出し側はあまりやりたくないし、処理速度を考えたら絶対ではないが、意識もしたくない処理ですね。
もし、このような処理を呼び出し側で行うと、呼び出し側のクラスの凝集度が悪くなる。
このページの利用によって発生した、いかなる損害について、このホームページの作成者は責任を負いません。
このページの間違いや嘘を見つけた方、このページに書いて欲しい情報がある方は
メールをお願いします。
Microsoft 、Windows 、Visual Basic および Excel は米国Microsoft
Corporationの米国およびその他の国における登録商標または商標です。
ここではExcel® をエクセル、Visual Basic® for Applications をVBAと表記する場合があります。
Mac 、Mac OS 、Mac OS X は米国Apple Computer,Inc.の登録商標または商標です。
その他、社名および商品名、システム名称などは、一般に各社の商標または登録商標です。
このホームページの作成者はこれらの会社とはいっさい関係がありません。